* Add support for multiple remote projects per Team (#6009)

* update fetching of teams

* create and delete remote projects

* backend project sync using the new teamProjectId in the API

* indicator

* use team api to get organization data

* handle logged out state

* remove remote from duplicate modal

* remaining insomnia fetch fixes

* fix ts issues

* fix ts log issue

* fix ts error

* fix ts update

* fix tests

* remove log

* add types to insomniaFetch

* named arguments in vcs

---------

Co-authored-by: jackkav <jackkav@gmail.com>

* Project Presence (#6079)

* fix ts log issue

* fix ts update

* update fetching of teams

* create and delete remote projects

* real-time

* update api changes

* check for successful response

* get user profile

* cleanup

* update fetch

* update network status

* fix for insomniaFetch new api

* insomnia fetch from window

* fix missing stat

* fix project dropdown

* update avatar

* update presence when closing the app

* update the presence every minute

* cleanup presence

* use eventsource and improve debugging

* Cloud only projects (#6167)

* Add support for multiple remote projects per Team (#6009)

* update fetching of teams

* create and delete remote projects

* backend project sync using the new teamProjectId in the API

* indicator

* use team api to get organization data

* handle logged out state

* remove remote from duplicate modal

* remaining insomnia fetch fixes

* fix ts issues

* fix ts log issue

* fix ts error

* fix ts update

* fix tests

* remove log

* add types to insomniaFetch

* named arguments in vcs

---------

Co-authored-by: jackkav <jackkav@gmail.com>

* login routes

* cleanup logged in state

* update organizations

* fixes

* update migration

* auto init sync on workspaces without git

* fix auto init sync

* checkpoint

* update import options in empty project pane

* responsive styles

* update package-lock

* join an org in sidebar

* readability improvements

* move modals and root loader to org

* cleanup root

* expire session take 1

* cleanup default org id

* fix ts issue

---------

Co-authored-by: jackkav <jackkav@gmail.com>

* Add Scratch Pad collection (#6221)

* add scratchpad collection

* filter scratchpad from cloud migration

* disable sync for scratchpad

* update settings for scratchpad

* log in rename

* check if user is logged in or has logged in before

* use organization api

* organizations api fixes

* update urls

* move modals to root

* update org navbar links

* lint fix

* type-check

* Add form for setting up the staging env

* add autolinking

* onboarding

* remove default org id

* staging urls

* avatar styles

* update urls

* use display name for orgs

* update settings modal with dev

* proper project deletions

* fix api calls perf

* sidebar improvements

* layout styles

* disable tests for now

* fix boolean

* fix data migration

* dev settings styles

* test init

* organization names

* link styles

* improve scratchpad banner styles

* http colors

* url bar styles

* spinner styles

* breadcrumbs styles

* help and feedback links

* settings to root

* onboarding

* fetch remote projects on org nav

* update avatar styles

* use name initials in avatars

* don't allow to delete default organization project

* add scratchpad checks

* tests

* workspace settings tabs types

* export all workspaces

* fix types and personal org

* project permission checks

* continue with sso

* organization avatars

* project presence avatars

* fix privacy/terms links

* add the no-wrap classname

* update user name and email in the app

* fix delete action

* ai fetching

* generate tests in sequence to help with rate limiting

* wip testing

* wip test

* improve test and migration script

* fix ts

* local to cloud projects test

* set local-to-cloud-projects.test as slow

* fix e2e tests

* update settings tests

* update more apis that changed from teams -> organizations

* simplify remote project migration

* org.branding can be undefined

* fix imports issue in sr

* remove .only

* remove unused gql query

* fix onboarding height jump

* trust some rnd and upload artifacts on failure

* fix env vars replacement on prod

* fix constant name

* bring back checks

* fix inso test

* add temp changes

* fix inconsistent response handling

* handle bad auth code errors

* show email when logged in

* remove the concept of default_project

* cleanup auth styles

* fix: use scratchpad constants wherever needed and remove seed

* fix sentry lint error

* migrate with update

* add scratch pad fixture and typing

* refactor pushSnapshotOnInitialize to always work

* remove console.log

* remove account from preferences

* improve trail-lines styles

* fix project sidebar scroll issue

* only create diff of projects

* fix lint

* sync

* feat: add plan upgrading modal for git sync (#6516)

* feat: add plan upgrading modal for git sync

* feat: add plan upgrading modal to project git menu and grid menu

* fix: use JSON.parse for getting flag value

* update ask modal

* remove git option from workspace settings

---------

Co-authored-by: gatzjames <jamesgatzos@gmail.com>

* sort projectswith default at top

* create local copies of remotes

* update presence exit update

* renames

* fix deleting/renaming projects with remoteId

* remoteId instead of projectId

* remote-collections

* fix initializeProjectForTeam

* fix missing parentId in remote projects

* add missing billing api

* add migration page and check for migrations

* cleanup project sync logic

* fix remote projects updating

* add notes

* fix backend-project test

* fix: use features API for fetching feature list (#6538)

* members -> collaborators

* remove dev settings

* use shouldRunMigrations in onboarding

* fix empty pane styles

* remove beforeUnload for presence

* show expiry info

* better error for upgrade in new project action

* extend retry period

* fallback and control revalidate

* add pending indicator for switching organizations

* fix exports (#6553)

* Sync Organizations (#6551)

* organization cache and updates

* error handling in org sync

* sort organizations

* clean up sort

* org sort and avatar fallback

---------

Co-authored-by: jackkav <jackkav@gmail.com>

* Presence updates (#6552)

* use remoteId for presence

* use project loader for the active project

* fix in present users

* logic clean

* match remoteId checks

---------

Co-authored-by: jackkav <jackkav@gmail.com>

* add default color to loading indicator

* fix redirect loop when there are no projects

* scratchpad fallback on initial route load

* re-enable ai check

* update error in renameProject

* db query to get projects in workspace

* review fix

* comments

* remove initModelFrom magic

* fix lint issue

---------

Co-authored-by: jackkav <jackkav@gmail.com>
Co-authored-by: Mark Kim <mark.kim@konghq.com>
Co-authored-by: Filipe Freire <livrofubia@gmail.com>
Co-authored-by: Hexxa <hexxa@outlook.com>
This commit is contained in:
authored and GitHub committed 2023-09-24 23:12:50 +00:00
1 parent 3628ddc5ad
commit 6ef9a46814
204 files changed
+5927 -2298

No files matched your search

+2 -2
View File
@@ -18,8 +18,6 @@ concurrency:
jobs:
Test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- name: Checkout branch
uses: actions/checkout@v3
@@ -103,8 +101,10 @@ jobs:
- name: Smoke test Inso CLI
run: npm run test:smoke:cli
# This step should always run even when previous steps fail
- name: Upload smoke test traces
uses: actions/upload-artifact@v3
if: failure()
with:
if-no-files-found: ignore
name: ubuntu-smoke-test-traces-${{ github.run_number }}
+3
View File
@@ -9,4 +9,7 @@
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "modifications",
"editor.defaultFormatter": "vscode.typescript-language-features",
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
}
+6
View File
@@ -13888,6 +13888,11 @@
"@grpc/grpc-js": "^1.0.0"
}
},
"node_modules/gsap": {
"version": "3.12.2",
"resolved": "https://registry.npmjs.org/gsap/-/gsap-3.12.2.tgz",
"integrity": "sha512-EkYnpG8qHgYBFAwsgsGEqvT1WUidX0tt/ijepx7z8EUJHElykg91RvW1XbkT59T0gZzzszOpjQv7SE41XuIXyQ=="
},
"node_modules/har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -24562,6 +24567,7 @@
"electron-context-menu": "^3.6.1",
"electron-log": "^4.4.8",
"grpc-reflection-js": "0.3.0",
"gsap": "^3.11.3",
"hawk": "9.0.1",
"hkdf": "^0.0.2",
"hosted-git-info": "5.2.1",
File diff suppressed because one or more lines are too long.
@@ -0,0 +1,8 @@
{"_id":"jar_477c547643674a53b75ec94371a59119","type":"CookieJar","parentId":"wrk_1b49626a0a9442b7b9474a1f3493bb5d","modified":1694513741482,"created":1694513741482,"name":"Default Jar","cookies":[]}
{"_id":"jar_5715ba490d323a1c17eddd5670b87527f86c23df","type":"CookieJar","parentId":"wrk_a528e60334a54420a7b384bae215ad1b","modified":1694436050045,"created":1694436050045,"name":"Default Jar","cookies":[]}
{"_id":"jar_727e68a0650a9198b46e09fe922ebdf2c4b14ee9","type":"CookieJar","parentId":"wrk_f3246c005c9d48ed9e35724415c962d6","modified":1694435944034,"created":1694435944034,"name":"Default Jar","cookies":[]}
{"_id":"jar_7b77a9be2508777ca03ff78df0ae609fc5f582bd","type":"CookieJar","parentId":"wrk_3f71ff5dcf5343169b9a67236f9deafe","modified":1694513691440,"created":1694513691440,"name":"Default Jar","cookies":[]}
{"_id":"jar_ab007691f15cfc166d22b053624849abab40c5f7","type":"CookieJar","parentId":"wrk_ef815fde95ce489aa225fc4408a04bf7","modified":1694436238621,"created":1694436238621,"name":"Default Jar","cookies":[]}
{"_id":"jar_b289a3371fe1228038a8a1df06cc2d0934f6b4f3","type":"CookieJar","parentId":"wrk_55a8240d025044d3a40eb40956126bec","modified":1694513468821,"created":1694513468821,"name":"Default Jar","cookies":[]}
{"_id":"jar_ce5c6ddfabc8dac33df7b4d14509356c9d280eb8","type":"CookieJar","parentId":"wrk_7c9f917b97cb4a43bb402ace6df1b107","modified":1694513835062,"created":1694513835062,"name":"Default Jar","cookies":[]}
{"_id":"jar_dfc984a037a5edccac6000064716590ad1628ad9","type":"CookieJar","parentId":"wrk_d783eca2fa46457c9f02a221ec862458","modified":1694513890792,"created":1694513890792,"name":"Default Jar","cookies":[]}
@@ -0,0 +1,12 @@
{"_id":"env_05e568304a74414b8b19bec3bae0e38d","type":"Environment","parentId":"env_5715ba490d323a1c17eddd5670b87527f86c23df","modified":1694436082762,"created":1694436082762,"name":"OpenAPI env petstore.swagger.io","data":{"scheme":"https","base_path":"/v2","host":"petstore.swagger.io"},"dataPropertyOrder":null,"color":null,"isPrivate":false,"metaSortKey":1694436082762}
{"_id":"env_284ec449cf894ffd958b9b54ad598c02","type":"Environment","parentId":"wrk_1b49626a0a9442b7b9474a1f3493bb5d","modified":1694513741462,"created":1694513741462,"name":"Base Environment","data":{},"dataPropertyOrder":null,"color":null,"isPrivate":false,"metaSortKey":1694513468817}
{"_id":"env_5715ba490d323a1c17eddd5670b87527f86c23df","type":"Environment","parentId":"wrk_a528e60334a54420a7b384bae215ad1b","modified":1694436050043,"created":1694436050043,"name":"Base Environment","data":{},"dataPropertyOrder":null,"color":null,"isPrivate":false,"metaSortKey":1694436050043}
{"_id":"env_727e68a0650a9198b46e09fe922ebdf2c4b14ee9","type":"Environment","parentId":"wrk_f3246c005c9d48ed9e35724415c962d6","modified":1694436015076,"created":1694435944033,"name":"Base Environment","data":{"planet":"earth"},"dataPropertyOrder":{"&":["planet"]},"color":null,"isPrivate":false,"metaSortKey":1694435944033}
{"_id":"env_7b77a9be2508777ca03ff78df0ae609fc5f582bd","type":"Environment","parentId":"wrk_3f71ff5dcf5343169b9a67236f9deafe","modified":1694513691435,"created":1694513691435,"name":"Base Environment","data":{},"dataPropertyOrder":null,"color":null,"isPrivate":false,"metaSortKey":1694513691435}
{"_id":"env_84795a9d18884f0fa11582cc88c0f206","type":"Environment","parentId":"env_b289a3371fe1228038a8a1df06cc2d0934f6b4f3","modified":1694513478190,"created":1694513478190,"name":"OpenAPI env petstore.swagger.io","data":{"scheme":"https","base_path":"/v2","host":"petstore.swagger.io"},"dataPropertyOrder":null,"color":null,"isPrivate":false,"metaSortKey":1694513478190}
{"_id":"env_ab007691f15cfc166d22b053624849abab40c5f7","type":"Environment","parentId":"wrk_ef815fde95ce489aa225fc4408a04bf7","modified":1694436238604,"created":1628147455088,"name":"Base Environment","data":{},"dataPropertyOrder":null,"color":null,"isPrivate":false,"metaSortKey":1628147455088}
{"_id":"env_ae8fb881d7f14abbb60c27c82dcf6072","type":"Environment","parentId":"env_727e68a0650a9198b46e09fe922ebdf2c4b14ee9","modified":1694436005646,"created":1694435987858,"name":"Mars","data":{"planet":"mars"},"dataPropertyOrder":{"&":["planet"]},"color":null,"isPrivate":false,"metaSortKey":1694435987858}
{"_id":"env_b289a3371fe1228038a8a1df06cc2d0934f6b4f3","type":"Environment","parentId":"wrk_55a8240d025044d3a40eb40956126bec","modified":1694513468817,"created":1694513468817,"name":"Base Environment","data":{},"dataPropertyOrder":null,"color":null,"isPrivate":false,"metaSortKey":1694513468817}
{"_id":"env_ce5c6ddfabc8dac33df7b4d14509356c9d280eb8","type":"Environment","parentId":"wrk_7c9f917b97cb4a43bb402ace6df1b107","modified":1694513835049,"created":1694513835049,"name":"Base Environment","data":{},"dataPropertyOrder":null,"color":null,"isPrivate":false,"metaSortKey":1694513835050}
{"_id":"env_dfc984a037a5edccac6000064716590ad1628ad9","type":"Environment","parentId":"wrk_d783eca2fa46457c9f02a221ec862458","modified":1694513890780,"created":1694513890780,"name":"Base Environment","data":{},"dataPropertyOrder":null,"color":null,"isPrivate":false,"metaSortKey":1694513890780}
{"_id":"env_e123dd1aa0b14e27b25f162787fa90d6","type":"Environment","parentId":"env_284ec449cf894ffd958b9b54ad598c02","modified":1694513741464,"created":1694513741464,"name":"OpenAPI env petstore.swagger.io","data":{"scheme":"https","base_path":"/v2","host":"petstore.swagger.io"},"dataPropertyOrder":null,"color":null,"isPrivate":false,"metaSortKey":1694513478190}
@@ -0,0 +1,4 @@
{"_id":"git_1fded700bfb74aa483560e116866d25e","type":"GitRepository","parentId":null,"modified":1694436298203,"created":1694436297415,"needsFullClone":false,"uri":"https://github.com/gatzjames/insomnia-git-example.git","credentials":{"username":"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","token":"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","oauth2format":"github"},"author":{"name":"gatzjames","email":"jamesgatzos@gmail.com"},"uriNeedsMigration":false}
{"_id":"git_82bf4ce708514ba4a61e5a23a644e0d7","type":"GitRepository","parentId":null,"modified":1694513652868,"created":1694513651705,"needsFullClone":false,"uri":"https://github.com/gatzjames/insomnia-git-example.git","credentials":{"username":"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","token":"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","oauth2format":"github"},"author":{"name":"gatzjames","email":"jamesgatzos@gmail.com"},"uriNeedsMigration":false}
{"_id":"git_a02b558275414a518e6107c3e85e405a","type":"GitRepository","parentId":null,"modified":1694513701781,"created":1694513700687,"needsFullClone":false,"uri":"https://github.com/gatzjames/insomnia-git-example.git","credentials":{"username":"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","token":"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","oauth2format":"github"},"author":{"name":"gatzjames","email":"jamesgatzos@gmail.com"},"uriNeedsMigration":false}
{"_id":"git_da0217efdd80460faa2f153c1e871083","type":"GitRepository","parentId":null,"modified":1694513852485,"created":1694513851549,"needsFullClone":false,"uri":"https://github.com/gatzjames/insomnia-git-example.git","credentials":{"username":"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","token":"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","oauth2format":"github"},"author":{"name":"gatzjames","email":"jamesgatzos@gmail.com"},"uriNeedsMigration":false}
@@ -0,0 +1,5 @@
{"_id":"proj_default-project","type":"Project","parentId":null,"modified":1694435924693,"created":1694435924693,"name":"Insomnia","remoteId":null}
{"_id":"proj_f5359773e8b544c2bfeec86c95b978dc","type":"Project","parentId":null,"modified":1694513815752,"created":1694436032201,"name":"Local Project (GIT)","remoteId":null}
{"_id":"proj_777cc16ca5f3419fbc262df283d27bdf","type":"Project","parentId":null,"modified":1694513815752,"created":1694436032201,"name":"Local Project","remoteId":null}
{"_id":"proj_scratchpad","type":"Project","parentId":null,"modified":1694513815752,"created":1694436032201,"name":"Scratchpad","remoteId":null}
{"_id":"proj_team_195a6ce0edb1427eb2e8ba7b986072e4","type":"Project","parentId":null,"modified":1694513929456,"created":1694513929456,"name":"🪄 Legacy Remote Project","remoteId":"team_195a6ce0edb1427eb2e8ba7b986072e4"}
@@ -0,0 +1,59 @@
{"_id":"req_074eb9af1eb04f7da98424aff4f80b50","type":"Request","parentId":"fld_f5d684c7cb994f0abddd2af7b2574369","modified":1694513741665,"created":1694513741665,"url":"{{ _.base_url }}/user/login","name":"Logs user into the system","description":"","method":"GET","body":{},"parameters":[{"name":"username","disabled":false,"value":"string"},{"name":"password","disabled":false,"value":"string"}],"headers":[],"authentication":{},"metaSortKey":-1694513478225,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_0c44ae04191b4b26af4a1c4231f3ca26","type":"Request","parentId":"fld_41731ba5147d4132b0969fe7e1a1aff3","modified":1694436082789,"created":1694436082789,"url":"{{ _.base_url }}/user/createWithArray","name":"Creates list of users with given input array","description":"","method":"POST","body":{"mimeType":"application/json","text":"[\n {\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n }\n]"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694436082789,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_0d40d2c37e0c4c31af63098803aa6da9","type":"Request","parentId":"fld_cf6d9eae350248a1afac20cce84c80a4","modified":1694513741540,"created":1694513741540,"url":"{{ _.base_url }}/pet/findByTags","name":"Finds Pets by tags","description":"","method":"GET","body":{},"parameters":[{"name":"tags","disabled":false,"value":"string"}],"headers":[],"authentication":{},"metaSortKey":-1694513478202,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_13512e54128346f3ab1d67ad0494fa56","type":"Request","parentId":"fld_fd2217f91f9a48b6b60ba1ecdf21ddef","modified":1694513478197,"created":1694513478197,"url":"{{ _.base_url }}/pet","name":"Add a new pet to the store","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"string\"\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478198,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_145f3154cdcf4a77a8c79a848467704a","type":"Request","parentId":"fld_f5d684c7cb994f0abddd2af7b2574369","modified":1694513741679,"created":1694513741679,"url":"{{ _.base_url }}/user/{{ _.username }}","name":"Get user by user name","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478232,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_163e848a55f94c8096d53a70d5ca6ef9","type":"Request","parentId":"fld_0dc862678d1b4b62b519d4ebabccf25f","modified":1694436154213,"created":1694436082780,"url":"{{ _.base_url }}/pet/findByStatus","name":"Finds Pets by status","description":"","method":"GET","body":{},"parameters":[{"name":"status","disabled":false,"value":"available"}],"headers":[],"authentication":{},"metaSortKey":-1694436082780,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_1727645245ea4a8a9a485d3af1f8d2f3","type":"Request","parentId":"fld_fd2217f91f9a48b6b60ba1ecdf21ddef","modified":1694513478207,"created":1694513478207,"url":"{{ _.base_url }}/pet/{{ _.petId }}","name":"Deletes a pet","description":"","method":"DELETE","body":{},"parameters":[],"headers":[{"name":"api_key","disabled":true,"value":"string"}],"authentication":{},"metaSortKey":-1694513478207,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_192c75d1b70a47c0bbdb38a2ec592e5d","type":"Request","parentId":"fld_15d587ccb28a4438a0c4c1e42b3aebfe","modified":1694513741600,"created":1694513741600,"url":"{{ _.base_url }}/store/order","name":"Place an order for a pet","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"petId\": 0,\n \"quantity\": 0,\n \"shipDate\": \"2023-09-12T10:11:18.185Z\",\n \"status\": \"string\",\n \"complete\": true\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478211,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_1ca5010386a74c19ad9606d4258998fa","type":"Request","parentId":"fld_cf6d9eae350248a1afac20cce84c80a4","modified":1694513741524,"created":1694513741524,"url":"{{ _.base_url }}/pet","name":"Update an existing pet","description":"","method":"PUT","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"string\"\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478200,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_21d2291e0e944359bc57db4d4fb900bc","type":"Request","parentId":"fld_f5d684c7cb994f0abddd2af7b2574369","modified":1694513741673,"created":1694513741673,"url":"{{ _.base_url }}/user/logout","name":"Logs out current logged in user session","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478229,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_2b30b68997304e1ab09fdbe2d3cc3767","type":"Request","parentId":"fld_0dc862678d1b4b62b519d4ebabccf25f","modified":1694436082781,"created":1694436082781,"url":"{{ _.base_url }}/pet/findByTags","name":"Finds Pets by tags","description":"","method":"GET","body":{},"parameters":[{"name":"tags","disabled":false,"value":"string"}],"headers":[],"authentication":{},"metaSortKey":-1694436082781,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_2b8a18c434654b2cb7b7d1a7d5000fdf","type":"Request","parentId":"fld_15d587ccb28a4438a0c4c1e42b3aebfe","modified":1694513741593,"created":1694513741593,"url":"{{ _.base_url }}/store/inventory","name":"Returns pet inventories by status","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478208,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_2c5dc56e4f2c438a89dbb8f7f74ed345","type":"Request","parentId":"fld_cf6d9eae350248a1afac20cce84c80a4","modified":1694513741565,"created":1694513741565,"url":"{{ _.base_url }}/pet/{{ _.petId }}","name":"Deletes a pet","description":"","method":"DELETE","body":{},"parameters":[],"headers":[{"name":"api_key","disabled":true,"value":"string"}],"authentication":{},"metaSortKey":-1694513478207,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_3049c3a7c24245c986b29e80ad5a44c6","type":"Request","parentId":"wrk_f3246c005c9d48ed9e35724415c962d6","modified":1694435970569,"created":1694435946705,"url":"https://mockbin.org/status/200","name":"Get list of rockets","description":"","method":"GET","body":{},"parameters":[],"headers":[{"name":"User-Agent","value":"insomnia/2023.5.8"}],"authentication":{},"metaSortKey":-1694435946705,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_32194eff4bfb4fa097d9a390eff6a775","type":"Request","parentId":"fld_f5d684c7cb994f0abddd2af7b2574369","modified":1694513741684,"created":1694513741684,"url":"{{ _.base_url }}/user/{{ _.username }}","name":"Updated user","description":"","method":"PUT","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478234,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_35eb88c4741948cbae6e9067d19b2f32","type":"Request","parentId":"fld_41731ba5147d4132b0969fe7e1a1aff3","modified":1694436082790,"created":1694436082790,"url":"{{ _.base_url }}/user/createWithList","name":"Creates list of users with given input array","description":"","method":"POST","body":{"mimeType":"application/json","text":"[\n {\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n }\n]"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694436082790,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_3b4ca2e394bb486ab0242ddf03035d38","type":"Request","parentId":"fld_41731ba5147d4132b0969fe7e1a1aff3","modified":1694436082788,"created":1694436082788,"url":"{{ _.base_url }}/user","name":"Create user","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694436082788,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_40504764445b424b9931d242d568a067","type":"Request","parentId":"fld_0dc862678d1b4b62b519d4ebabccf25f","modified":1694436082784,"created":1694436082784,"url":"{{ _.base_url }}/pet/{{ _.petId }}","name":"Deletes a pet","description":"","method":"DELETE","body":{},"parameters":[],"headers":[{"name":"api_key","disabled":true,"value":"string"}],"authentication":{},"metaSortKey":-1694436082784,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_42f11c00991b4d5890af3f8b751f6842","type":"Request","parentId":"fld_e665ff77102645bf888faaa3af3287a9","modified":1694513478215,"created":1694513478215,"url":"{{ _.base_url }}/store/order/{{ _.orderId }}","name":"Find purchase order by ID","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478215,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_45a81258cef8479cbf112d14c44b1da3","type":"Request","parentId":"fld_b6964b1458c749e490815c94816c4ed9","modified":1694436082786,"created":1694436082786,"url":"{{ _.base_url }}/store/order/{{ _.orderId }}","name":"Find purchase order by ID","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694436082786,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_48b9de3ca2f941798e5da7ffadbdd6bd","type":"Request","parentId":"fld_17cc4f5762c5423592d1a384461adf18","modified":1694513478235,"created":1694513478235,"url":"{{ _.base_url }}/user/{{ _.username }}","name":"Delete user","description":"","method":"DELETE","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478235,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_4fc95d07f7704bed9dc78bb845ef76e1","type":"Request","parentId":"fld_15d587ccb28a4438a0c4c1e42b3aebfe","modified":1694513741616,"created":1694513741616,"url":"{{ _.base_url }}/store/order/{{ _.orderId }}","name":"Find purchase order by ID","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478215,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_4ffad86de65a4388bdba565cabacee1a","type":"Request","parentId":"fld_0dc862678d1b4b62b519d4ebabccf25f","modified":1694436082782,"created":1694436082782,"url":"{{ _.base_url }}/pet/{{ _.petId }}","name":"Find pet by ID","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694436082782,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_529632695f3e479bbe9229ae2f63c32c","type":"Request","parentId":"fld_15d587ccb28a4438a0c4c1e42b3aebfe","modified":1694513741625,"created":1694513741625,"url":"{{ _.base_url }}/store/order/{{ _.orderId }}","name":"Delete purchase order by ID","description":"","method":"DELETE","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478217,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_5d0f087267a342e1800541654b4ee895","type":"Request","parentId":"fld_f5d684c7cb994f0abddd2af7b2574369","modified":1694513741636,"created":1694513741636,"url":"{{ _.base_url }}/user","name":"Create user","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478219,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_6391c7cb69f84ca6bcd88920875cad4c","type":"Request","parentId":"fld_41731ba5147d4132b0969fe7e1a1aff3","modified":1694436082792,"created":1694436082792,"url":"{{ _.base_url }}/user/logout","name":"Logs out current logged in user session","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694436082792,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_6724a9231d6e40278a7f5d270c40617a","type":"Request","parentId":"fld_e665ff77102645bf888faaa3af3287a9","modified":1694513478208,"created":1694513478208,"url":"{{ _.base_url }}/store/inventory","name":"Returns pet inventories by status","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478208,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_68172cea6e4942a3b914e5ebf1834bcd","type":"Request","parentId":"fld_fd2217f91f9a48b6b60ba1ecdf21ddef","modified":1694513478205,"created":1694513478205,"url":"{{ _.base_url }}/pet/{{ _.petId }}","name":"Updates a pet in the store with form data","description":"","method":"POST","body":{"mimeType":"application/x-www-form-urlencoded"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/x-www-form-urlencoded"}],"authentication":{},"metaSortKey":-1694513478205,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_6945f2841b8b4daf9f6141d7a06c6d62","type":"Request","parentId":"fld_41731ba5147d4132b0969fe7e1a1aff3","modified":1694436082794,"created":1694436082794,"url":"{{ _.base_url }}/user/{{ _.username }}","name":"Delete user","description":"","method":"DELETE","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694436082794,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_74bbe9b9290c4bb991e31277d0ca06ce","type":"Request","parentId":"fld_0dc862678d1b4b62b519d4ebabccf25f","modified":1694436082778,"created":1694436082778,"url":"{{ _.base_url }}/pet","name":"Add a new pet to the store","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"string\"\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694436082778,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_7885c94ca5444575bf245fe35d99bb2b","type":"Request","parentId":"fld_17cc4f5762c5423592d1a384461adf18","modified":1694513478223,"created":1694513478223,"url":"{{ _.base_url }}/user/createWithList","name":"Creates list of users with given input array","description":"","method":"POST","body":{"mimeType":"application/json","text":"[\n {\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n }\n]"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478223,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_7d18e1be691a4b6eb4c048bf2024f42c","type":"Request","parentId":"fld_b6964b1458c749e490815c94816c4ed9","modified":1694436082785,"created":1694436082785,"url":"{{ _.base_url }}/store/order","name":"Place an order for a pet","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"petId\": 0,\n \"quantity\": 0,\n \"shipDate\": \"2023-09-11T12:41:22.746Z\",\n \"status\": \"string\",\n \"complete\": true\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694436082785,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_8a19defaeb904531896c36af722b7489","type":"Request","parentId":"fld_41731ba5147d4132b0969fe7e1a1aff3","modified":1694436082793,"created":1694436082793,"url":"{{ _.base_url }}/user/{{ _.username }}","name":"Updated user","description":"","method":"PUT","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694436082793,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_8c5f57330ff04979b508bdd88d893ebd","type":"Request","parentId":"fld_cf6d9eae350248a1afac20cce84c80a4","modified":1694513741531,"created":1694513741531,"url":"{{ _.base_url }}/pet/findByStatus","name":"Finds Pets by status","description":"","method":"GET","body":{},"parameters":[{"name":"status","disabled":false,"value":"available"}],"headers":[],"authentication":{},"metaSortKey":-1694513478201,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_8f33c838b6d046979d9ceb9b4bece221","type":"Request","parentId":"fld_0dc862678d1b4b62b519d4ebabccf25f","modified":1694436082779,"created":1694436082779,"url":"{{ _.base_url }}/pet","name":"Update an existing pet","description":"","method":"PUT","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"string\"\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694436082779,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_916d759fb4d242b6820d934757004499","type":"Request","parentId":"fld_41731ba5147d4132b0969fe7e1a1aff3","modified":1694436082791,"created":1694436082791,"url":"{{ _.base_url }}/user/login","name":"Logs user into the system","description":"","method":"GET","body":{},"parameters":[{"name":"username","disabled":false,"value":"string"},{"name":"password","disabled":false,"value":"string"}],"headers":[],"authentication":{},"metaSortKey":-1694436082791,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_91ff9bd78c0145e1aaddc0c35e8272d7","type":"Request","parentId":"fld_fd2217f91f9a48b6b60ba1ecdf21ddef","modified":1694513478202,"created":1694513478202,"url":"{{ _.base_url }}/pet/findByTags","name":"Finds Pets by tags","description":"","method":"GET","body":{},"parameters":[{"name":"tags","disabled":false,"value":"string"}],"headers":[],"authentication":{},"metaSortKey":-1694513478202,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_941bb4c1300444a8b8f5764bf544a720","type":"Request","parentId":"fld_e665ff77102645bf888faaa3af3287a9","modified":1694513478211,"created":1694513478211,"url":"{{ _.base_url }}/store/order","name":"Place an order for a pet","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"petId\": 0,\n \"quantity\": 0,\n \"shipDate\": \"2023-09-12T10:11:18.185Z\",\n \"status\": \"string\",\n \"complete\": true\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478211,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_99a7c1e90e4845988eabd18e45de05e2","type":"Request","parentId":"fld_17cc4f5762c5423592d1a384461adf18","modified":1694513478232,"created":1694513478232,"url":"{{ _.base_url }}/user/{{ _.username }}","name":"Get user by user name","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478232,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_9b14424c0b764e26958fae1f9fd6a908","type":"Request","parentId":"fld_f5d684c7cb994f0abddd2af7b2574369","modified":1694513741693,"created":1694513741693,"url":"{{ _.base_url }}/user/{{ _.username }}","name":"Delete user","description":"","method":"DELETE","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478235,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_a6619ad15c1c46209e5d3777d2015536","type":"Request","parentId":"fld_b6964b1458c749e490815c94816c4ed9","modified":1694436082785,"created":1694436082785,"url":"{{ _.base_url }}/store/inventory","name":"Returns pet inventories by status","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694436082785,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_ae7eb298851f48379de12ff46bd9d1ad","type":"Request","parentId":"fld_e665ff77102645bf888faaa3af3287a9","modified":1694513478217,"created":1694513478217,"url":"{{ _.base_url }}/store/order/{{ _.orderId }}","name":"Delete purchase order by ID","description":"","method":"DELETE","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478217,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_b223a210e2b64c42b6ac98afec1e9552","type":"Request","parentId":"fld_fd2217f91f9a48b6b60ba1ecdf21ddef","modified":1694513478200,"created":1694513478200,"url":"{{ _.base_url }}/pet","name":"Update an existing pet","description":"","method":"PUT","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"string\"\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478200,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_bc90a18e061a41938f0661ab4fff9a3b","type":"Request","parentId":"fld_b6964b1458c749e490815c94816c4ed9","modified":1694436082787,"created":1694436082787,"url":"{{ _.base_url }}/store/order/{{ _.orderId }}","name":"Delete purchase order by ID","description":"","method":"DELETE","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694436082787,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_c81095cc13414914a581b82f24bedf91","type":"Request","parentId":"fld_f5d684c7cb994f0abddd2af7b2574369","modified":1694513741658,"created":1694513741658,"url":"{{ _.base_url }}/user/createWithList","name":"Creates list of users with given input array","description":"","method":"POST","body":{"mimeType":"application/json","text":"[\n {\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n }\n]"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478223,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_cbe176232cac4dfc9ac2be7302623f03","type":"Request","parentId":"fld_fd2217f91f9a48b6b60ba1ecdf21ddef","modified":1694513478204,"created":1694513478204,"url":"{{ _.base_url }}/pet/{{ _.petId }}","name":"Find pet by ID","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478204,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_d108b051765444faa2ab920f166c8e99","type":"Request","parentId":"fld_f5d684c7cb994f0abddd2af7b2574369","modified":1694513741646,"created":1694513741646,"url":"{{ _.base_url }}/user/createWithArray","name":"Creates list of users with given input array","description":"","method":"POST","body":{"mimeType":"application/json","text":"[\n {\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n }\n]"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478221,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_d8314112ea8b494a9d2954949deef6c2","type":"Request","parentId":"fld_17cc4f5762c5423592d1a384461adf18","modified":1694513478229,"created":1694513478229,"url":"{{ _.base_url }}/user/logout","name":"Logs out current logged in user session","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478229,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_daa311e962424e52a98e51d5ddb4fa5e","type":"Request","parentId":"fld_17cc4f5762c5423592d1a384461adf18","modified":1694513478234,"created":1694513478234,"url":"{{ _.base_url }}/user/{{ _.username }}","name":"Updated user","description":"","method":"PUT","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478234,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_dbd2fe72a91946359532fbff416f25d7","type":"Request","parentId":"wrk_ef815fde95ce489aa225fc4408a04bf7","modified":1694436250026,"created":1694436242029,"url":"https://mockbin.org","name":"New Request","description":"","method":"GET","body":{},"parameters":[],"headers":[{"name":"User-Agent","value":"insomnia/2023.5.8"}],"authentication":{},"metaSortKey":-1694436242029,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_e66296d2c3b6452fb7a425975e045dcf","type":"Request","parentId":"fld_0dc862678d1b4b62b519d4ebabccf25f","modified":1694436082783,"created":1694436082783,"url":"{{ _.base_url }}/pet/{{ _.petId }}","name":"Updates a pet in the store with form data","description":"","method":"POST","body":{"mimeType":"application/x-www-form-urlencoded"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/x-www-form-urlencoded"}],"authentication":{},"metaSortKey":-1694436082783,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_e6c3e9c0bdb847b6a7049e2bd1b43a23","type":"Request","parentId":"fld_41731ba5147d4132b0969fe7e1a1aff3","modified":1694436082792,"created":1694436082792,"url":"{{ _.base_url }}/user/{{ _.username }}","name":"Get user by user name","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694436082792,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_e70fd54fa9284182a776a067d82c2476","type":"Request","parentId":"fld_17cc4f5762c5423592d1a384461adf18","modified":1694513478225,"created":1694513478225,"url":"{{ _.base_url }}/user/login","name":"Logs user into the system","description":"","method":"GET","body":{},"parameters":[{"name":"username","disabled":false,"value":"string"},{"name":"password","disabled":false,"value":"string"}],"headers":[],"authentication":{},"metaSortKey":-1694513478225,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_e75682413e444776a85d228211e38285","type":"Request","parentId":"fld_cf6d9eae350248a1afac20cce84c80a4","modified":1694513741515,"created":1694513741515,"url":"{{ _.base_url }}/pet","name":"Add a new pet to the store","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"string\"\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478198,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_e87d6b3019e44dc797296b6bef80371e","type":"Request","parentId":"fld_17cc4f5762c5423592d1a384461adf18","modified":1694513478221,"created":1694513478221,"url":"{{ _.base_url }}/user/createWithArray","name":"Creates list of users with given input array","description":"","method":"POST","body":{"mimeType":"application/json","text":"[\n {\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n }\n]"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478221,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_e972c7bc07bc42f7862b4d0888bbb7b5","type":"Request","parentId":"fld_cf6d9eae350248a1afac20cce84c80a4","modified":1694513741546,"created":1694513741546,"url":"{{ _.base_url }}/pet/{{ _.petId }}","name":"Find pet by ID","description":"","method":"GET","body":{},"parameters":[],"headers":[],"authentication":{},"metaSortKey":-1694513478204,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_f2a1313381bf471cb3e4e4d95bd67c9f","type":"Request","parentId":"fld_17cc4f5762c5423592d1a384461adf18","modified":1694513478219,"created":1694513478219,"url":"{{ _.base_url }}/user","name":"Create user","description":"","method":"POST","body":{"mimeType":"application/json","text":"{\n \"id\": 0,\n \"username\": \"string\",\n \"firstName\": \"string\",\n \"lastName\": \"string\",\n \"email\": \"string\",\n \"password\": \"string\",\n \"phone\": \"string\",\n \"userStatus\": 0\n}"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/json"}],"authentication":{},"metaSortKey":-1694513478219,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_f9f57fb269a04e9d8b810b988ce715d6","type":"Request","parentId":"fld_cf6d9eae350248a1afac20cce84c80a4","modified":1694513741557,"created":1694513741557,"url":"{{ _.base_url }}/pet/{{ _.petId }}","name":"Updates a pet in the store with form data","description":"","method":"POST","body":{"mimeType":"application/x-www-form-urlencoded"},"parameters":[],"headers":[{"name":"Content-Type","disabled":false,"value":"application/x-www-form-urlencoded"}],"authentication":{},"metaSortKey":-1694513478205,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
{"_id":"req_fd68a98e5f2a4a61b7d1552aa083e12a","type":"Request","parentId":"fld_fd2217f91f9a48b6b60ba1ecdf21ddef","modified":1694513478201,"created":1694513478201,"url":"{{ _.base_url }}/pet/findByStatus","name":"Finds Pets by status","description":"","method":"GET","body":{},"parameters":[{"name":"status","disabled":false,"value":"available"}],"headers":[],"authentication":{},"metaSortKey":-1694513478201,"isPrivate":false,"settingStoreCookies":true,"settingSendCookies":true,"settingDisableRenderRequestBody":false,"settingEncodeUrl":true,"settingRebuildPath":true,"settingFollowRedirects":"global"}
@@ -0,0 +1,9 @@
{"_id":"fld_0dc862678d1b4b62b519d4ebabccf25f","type":"RequestGroup","parentId":"wrk_a528e60334a54420a7b384bae215ad1b","modified":1694436082773,"created":1694436082773,"name":"pet","description":"Everything about your Pets","environment":{},"environmentPropertyOrder":null,"metaSortKey":-1694436082773}
{"_id":"fld_15d587ccb28a4438a0c4c1e42b3aebfe","type":"RequestGroup","parentId":"wrk_1b49626a0a9442b7b9474a1f3493bb5d","modified":1694513741584,"created":1694513741584,"name":"store","description":"Access to Petstore orders","environment":{},"environmentPropertyOrder":null,"metaSortKey":-1694513478194}
{"_id":"fld_17cc4f5762c5423592d1a384461adf18","type":"RequestGroup","parentId":"wrk_55a8240d025044d3a40eb40956126bec","modified":1694513478196,"created":1694513478196,"name":"user","description":"Operations about user","environment":{},"environmentPropertyOrder":null,"metaSortKey":-1694513478196}
{"_id":"fld_41731ba5147d4132b0969fe7e1a1aff3","type":"RequestGroup","parentId":"wrk_a528e60334a54420a7b384bae215ad1b","modified":1694436082777,"created":1694436082777,"name":"user","description":"Operations about user","environment":{},"environmentPropertyOrder":null,"metaSortKey":-1694436082777}
{"_id":"fld_b6964b1458c749e490815c94816c4ed9","type":"RequestGroup","parentId":"wrk_a528e60334a54420a7b384bae215ad1b","modified":1694436082775,"created":1694436082775,"name":"store","description":"Access to Petstore orders","environment":{},"environmentPropertyOrder":null,"metaSortKey":-1694436082775}
{"_id":"fld_cf6d9eae350248a1afac20cce84c80a4","type":"RequestGroup","parentId":"wrk_1b49626a0a9442b7b9474a1f3493bb5d","modified":1694513741509,"created":1694513741509,"name":"pet","description":"Everything about your Pets","environment":{},"environmentPropertyOrder":null,"metaSortKey":-1694513478192}
{"_id":"fld_e665ff77102645bf888faaa3af3287a9","type":"RequestGroup","parentId":"wrk_55a8240d025044d3a40eb40956126bec","modified":1694513478194,"created":1694513478194,"name":"store","description":"Access to Petstore orders","environment":{},"environmentPropertyOrder":null,"metaSortKey":-1694513478194}
{"_id":"fld_f5d684c7cb994f0abddd2af7b2574369","type":"RequestGroup","parentId":"wrk_1b49626a0a9442b7b9474a1f3493bb5d","modified":1694513741632,"created":1694513741632,"name":"user","description":"Operations about user","environment":{},"environmentPropertyOrder":null,"metaSortKey":-1694513478196}
{"_id":"fld_fd2217f91f9a48b6b60ba1ecdf21ddef","type":"RequestGroup","parentId":"wrk_55a8240d025044d3a40eb40956126bec","modified":1694513478192,"created":1694513478192,"name":"pet","description":"Everything about your Pets","environment":{},"environmentPropertyOrder":null,"metaSortKey":-1694513478192}
@@ -0,0 +1,3 @@
{"_id":"reqm_3d151304a57144e7aec52dfe22227fcb","type":"RequestMeta","parentId":"req_3049c3a7c24245c986b29e80ad5a44c6","modified":1694513621353,"created":1694435946729,"previewMode":"friendly","responseFilter":"","responseFilterHistory":[],"activeResponseId":"res_12166e333b4245d58f5faa232c348b44","savedRequestBody":{},"pinned":false,"lastActive":1694513621011,"downloadPath":null,"expandedAccordionKeys":{}}
{"_id":"reqm_4cad9f930583499cab22d70531d557b6","type":"RequestMeta","parentId":"req_163e848a55f94c8096d53a70d5ca6ef9","modified":1694513822929,"created":1694436132724,"previewMode":"friendly","responseFilter":"","responseFilterHistory":[],"activeResponseId":null,"savedRequestBody":{},"pinned":false,"lastActive":1694513822927,"downloadPath":null,"expandedAccordionKeys":{}}
{"_id":"reqm_f7d5118cb91d42d1a50f2a78c781f6bc","type":"RequestMeta","parentId":"req_dbd2fe72a91946359532fbff416f25d7","modified":1694513669923,"created":1694436242051,"previewMode":"friendly","responseFilter":"","responseFilterHistory":[],"activeResponseId":"res_bdef9b7f52ba4c91adfd0bd863c70156","savedRequestBody":{},"pinned":false,"lastActive":1694513669922,"downloadPath":null,"expandedAccordionKeys":{}}
@@ -0,0 +1,2 @@
{"_id":"rvr_7ff1fa7e4fe64dabbf1d9ba5ba56c79b","type":"RequestVersion","parentId":"req_dbd2fe72a91946359532fbff416f25d7","modified":1694436253725,"created":1694436253725,"compressedRequest":"H4sIAAAAAAAAE21QyU7DMBD9FeRzaFPXCU1u7EJICBU4IVRN4nFj1bWLPaFCVf+dCYtYxHHmzdtmJxZWi1pEfF7oRkuDRxKqSaXKaVEVU2kaY9SkNLLQRyIT9LpBvp7jc4+JeLGBiJ6uBoltXC3QzCaF0VgVLapZBSBlYVql8hnkqjGDxDpoaywyY1JWSk1LWeS5LDPRRgT6uVcyl1Um+uhYvSPapHo8Xod21Vg/CnHJYh7WQ54b3B58Z9KY2mg3ZINnbLBE6sIQ8fL8nscm6FdR7/bv6VmAMCZRPz5lokPQH8PuS/ohYTw8XnJJZr6A64el9SmsvYUxJ5yOitFM7JkNPXV8Z1v4sB4cWB3uQqRrZMvDP81suo32hUuL2oBLmImERNYv7yhEPA1hZZHDUOx/QOj1/8iZTdA4nPMBxs9vnLxX/S1+7tug8WH46i/+HJveOn0L1P1BLoJzYTtHbSO2xL5i6UIDTuzfAN32OFE/AgAA"}
{"_id":"rvr_b9e82de8e4df44a8bfc98cce22e4937d","type":"RequestVersion","parentId":"req_3049c3a7c24245c986b29e80ad5a44c6","modified":1694435971248,"created":1694435971248,"compressedRequest":"H4sIAAAAAAAAE21Ry07rMBD9lcrr0IbESZvsuPdyEWKDCqwQqib2tBnVtYs9AaGq/86EhwSIpec85pzxQa3IqlZFfFyVuW5MCXNT6EJXplnUXdHgIgdbgdamVpnilz0Ke4mPAyaWwR4ier4cLZ7jdrUuC12bPBe11Qu0DZbVvND6VAZ1YUeLXbC0JhTFad1oXVbNPK/qJlMmIvDXua4FydQQnbj3zPvUzma7YLYd+WmIm1li4CHNijwXXw+7MdoF8sRR4klYT6JwkZOAFpOJtGcKXjhjCuQ+jKkvzm/l2QX7otrD8a2QGDHGpNr7h0z1CPb9cfhccZcwnpxtpLcon8AN45B8CjtPIGmKclpNF+ooahi4Fx4ZeF89bhB3uAmRr1BWnvwoS+k60pPcQbVrcAkzlZCZ/OaGQ8S/IWwJJQzH4QuE3v6O/KMEncOlEDB+fNqft6rfzc+9CRbvxkN/0y+xG8jZa+D+B/I/OBeel2gpopETt2rjQgdOHV8B1feGK1ICAAA="}
@@ -0,0 +1,2 @@
{"_id":"res_12166e333b4245d58f5faa232c348b44","type":"Response","parentId":"req_3049c3a7c24245c986b29e80ad5a44c6","modified":1694435971253,"created":1694435971253,"statusCode":200,"statusMessage":"","httpVersion":"HTTP/2","contentType":"application/json; charset=utf-8","url":"https://mockbin.org/status/200","bytesRead":38,"bytesContent":38,"elapsedTime":381.818,"headers":[{"name":"date","value":"Mon, 11 Sep 2023 12:39:33 GMT"},{"name":"content-type","value":"application/json; charset=utf-8"},{"name":"content-length","value":"38"},{"name":"access-control-allow-origin","value":"*"},{"name":"access-control-allow-methods","value":"GET"},{"name":"access-control-allow-headers","value":"host,connection,accept-encoding,x-forwarded-for,cf-ray,x-forwarded-proto,cf-visitor,user-agent,accept,cdn-loop,cf-connecting-ip,x-request-id,x-forwarded-port,via,connect-time,x-request-start,total-route-time"},{"name":"access-control-allow-credentials","value":"true"},{"name":"x-powered-by","value":"mockbin"},{"name":"vary","value":"Accept, Accept-Encoding"},{"name":"etag","value":"W/\"26-tc4xT7f7mVsEKKLOEWnIg/voxtc\""},{"name":"via","value":"1.1 vegur"},{"name":"cf-cache-status","value":"DYNAMIC"},{"name":"report-to","value":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=miPfsyiWpJm9tu2MW7LXgMXvGoMBjgoWrTYaiyni%2FNe%2FhLrnMUMggweKHreYvw3Wdb97m3q1EO1aIq64p0BJVdhiJEEqRvTvYIQADjKPO3wF92BZNnWrP1hZNgDOeQ%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}"},{"name":"nel","value":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}"},{"name":"server","value":"cloudflare"},{"name":"cf-ray","value":"804ff960ffcf0a69-AMS"},{"name":"alt-svc","value":"h3=\":443\"; ma=86400"}],"timelinePath":"/Users/jamesgatz/Library/Application Support/Insomnia/responses/caa4e99f-3aec-418c-a6b8-e235cb9cf100.timeline","bodyPath":"/Users/jamesgatz/Library/Application Support/Insomnia/responses/bb1d4190-8057-4812-b9db-e3073031242d.response","bodyCompression":null,"error":"","requestVersionId":"rvr_b9e82de8e4df44a8bfc98cce22e4937d","settingStoreCookies":true,"settingSendCookies":true,"environmentId":null}
{"_id":"res_bdef9b7f52ba4c91adfd0bd863c70156","type":"Response","parentId":"req_dbd2fe72a91946359532fbff416f25d7","modified":1694436253730,"created":1694436253730,"statusCode":200,"statusMessage":"","httpVersion":"HTTP/2","contentType":"text/html; charset=utf-8","url":"https://mockbin.org/","bytesRead":10696,"bytesContent":10696,"elapsedTime":326.637,"headers":[{"name":"date","value":"Mon, 11 Sep 2023 12:44:15 GMT"},{"name":"content-type","value":"text/html; charset=utf-8"},{"name":"vary","value":"Accept-Encoding"},{"name":"via","value":"1.1 vegur"},{"name":"cf-cache-status","value":"DYNAMIC"},{"name":"report-to","value":"{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=%2FQ93Z%2FUYZDusNDucRzBELssFpK1QckLl728ZkJ%2Fo%2BYuPeBIsT1nhFp6gRkKglylrjA3YgknADybNMr9Cf2moPv%2B8hw%2F80QO0vxVQTTKJlUS9DZSCcK5aUGO9b1X4gQ%3D%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}"},{"name":"nel","value":"{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}"},{"name":"server","value":"cloudflare"},{"name":"cf-ray","value":"805000467d910a6c-AMS"},{"name":"alt-svc","value":"h3=\":443\"; ma=86400"}],"timelinePath":"/Users/jamesgatz/Library/Application Support/Insomnia/responses/4551ecf6-4d74-4aae-958a-a9b1b4e5cde0.timeline","bodyPath":"/Users/jamesgatz/Library/Application Support/Insomnia/responses/f34e1b3d-cba5-43de-be7a-3a699ffbde1c.response","bodyCompression":null,"error":"","requestVersionId":"rvr_7ff1fa7e4fe64dabbf1d9ba5ba56c79b","settingStoreCookies":true,"settingSendCookies":true,"environmentId":null}
File diff suppressed because one or more lines are too long.
@@ -0,0 +1,2 @@
{"_id":"sta_75eb607a69ce4fdba7c4056c9e56201d","type":"Stats","parentId":null,"modified":1694513922516,"created":1694435923608,"currentLaunch":1694513410381,"lastLaunch":1694503948477,"currentVersion":"2023.5.8","lastVersion":"2023.5.8","launches":5,"createdRequests":21,"deletedRequests":68,"executedRequests":6}
{"_id":"sta_75eb607a69ce4fdba7c4056c9e56201d","type":"Stats","parentId":null,"modified":1694513953000,"created":1694435923608,"currentLaunch":1694513952999,"lastLaunch":1694513410381,"currentVersion":"2023.5.8","lastVersion":"2023.5.8","launches":6,"createdRequests":21,"deletedRequests":68,"executedRequests":6}
@@ -0,0 +1,3 @@
{"_id":"ut_3778208cf3054e5fb9ddd5ca639a6271","type":"UnitTest","parentId":"uts_aeb27e8dade847ab89f53cab2c0eafbc","modified":1694436094618,"created":1694436076224,"requestId":"req_163e848a55f94c8096d53a70d5ca6ef9","name":"Returns 200","code":"const response1 = await insomnia.send();\nexpect(response1.status).to.equal(200);"}
{"_id":"ut_622a9d9239524358bad3418a35f4e4f7","type":"UnitTest","parentId":"uts_c547332ddcda43ca8e47b489519b170f","modified":1694513487822,"created":1694513487822,"requestId":null,"name":"Returns 200","code":"const response1 = await insomnia.send();\nexpect(response1.status).to.equal(200);"}
{"_id":"ut_d7e95a6a18fb4409bce4406ac9ea247f","type":"UnitTest","parentId":"uts_6d26df3191ab46a08fe2e5859754e1cf","modified":1694513741709,"created":1694513741709,"requestId":null,"name":"Returns 200","code":"const response1 = await insomnia.send();\nexpect(response1.status).to.equal(200);"}
@@ -0,0 +1,4 @@
{"_id":"utr_151e4ecb47784bacbea430c71dc6a90b","type":"UnitTestResult","parentId":"wrk_a528e60334a54420a7b384bae215ad1b","modified":1694436090299,"created":1694436090299,"results":{"stats":{"suites":1,"tests":1,"passes":0,"pending":0,"failures":1,"start":{"$$date":1694436090277},"end":{"$$date":1694436090299},"duration":22},"tests":[{"title":"Returns 200","fullTitle":"My Suite Returns 200","file":"/var/folders/_7/6ms57pwx6899ftqnx4cxcsf80000gn/T/insomnia-testing/0.37939980943090235-test.ts","duration":18,"currentRetry":0,"err":{"stack":"Error: attempted to output null or undefined value\n at file:///Applications/Insomnia.app/Contents/Resources/app.asar/index-f89f6e08.js:90:20151\n at /Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:2307:5\n at RawTask.call (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4583:19)\n at MutationObserver.flush (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4660:29)","message":"attempted to output null or undefined value","path":"url","location":{"line":1,"column":1},"type":"render","reason":"undefined","multiple":[{"path":"url","location":"[object Object]","type":"render","reason":"undefined","multiple":"Error: attempted to output null or undefined value"}]}}],"pending":[],"failures":[{"title":"Returns 200","fullTitle":"My Suite Returns 200","file":"/var/folders/_7/6ms57pwx6899ftqnx4cxcsf80000gn/T/insomnia-testing/0.37939980943090235-test.ts","duration":18,"currentRetry":0,"err":{"stack":"Error: attempted to output null or undefined value\n at file:///Applications/Insomnia.app/Contents/Resources/app.asar/index-f89f6e08.js:90:20151\n at /Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:2307:5\n at RawTask.call (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4583:19)\n at MutationObserver.flush (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4660:29)","message":"attempted to output null or undefined value","path":"url","location":{"line":1,"column":1},"type":"render","reason":"undefined","multiple":[{"path":"url","location":"[object Object]","type":"render","reason":"undefined","multiple":"Error: attempted to output null or undefined value"}]}}],"passes":[]}}
{"_id":"utr_257e8a95b57d4ce790d12a47fccb18d9","type":"UnitTestResult","parentId":"wrk_a528e60334a54420a7b384bae215ad1b","modified":1694436095101,"created":1694436095101,"results":{"stats":{"suites":1,"tests":1,"passes":0,"pending":0,"failures":1,"start":{"$$date":1694436095069},"end":{"$$date":1694436095101},"duration":32},"tests":[{"title":"Returns 200","fullTitle":"My Suite Returns 200","file":"/var/folders/_7/6ms57pwx6899ftqnx4cxcsf80000gn/T/insomnia-testing/0.46268860035276904-test.ts","duration":31,"currentRetry":0,"err":{"stack":"Error: attempted to output null or undefined value\n at file:///Applications/Insomnia.app/Contents/Resources/app.asar/index-f89f6e08.js:90:20151\n at /Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:2307:5\n at RawTask.call (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4583:19)\n at MutationObserver.flush (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4660:29)","message":"attempted to output null or undefined value","path":"url","location":{"line":1,"column":1},"type":"render","reason":"undefined","multiple":[{"path":"url","location":"[object Object]","type":"render","reason":"undefined","multiple":"Error: attempted to output null or undefined value"}]}}],"pending":[],"failures":[{"title":"Returns 200","fullTitle":"My Suite Returns 200","file":"/var/folders/_7/6ms57pwx6899ftqnx4cxcsf80000gn/T/insomnia-testing/0.46268860035276904-test.ts","duration":31,"currentRetry":0,"err":{"stack":"Error: attempted to output null or undefined value\n at file:///Applications/Insomnia.app/Contents/Resources/app.asar/index-f89f6e08.js:90:20151\n at /Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:2307:5\n at RawTask.call (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4583:19)\n at MutationObserver.flush (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4660:29)","message":"attempted to output null or undefined value","path":"url","location":{"line":1,"column":1},"type":"render","reason":"undefined","multiple":[{"path":"url","location":"[object Object]","type":"render","reason":"undefined","multiple":"Error: attempted to output null or undefined value"}]}}],"passes":[]}}
{"_id":"utr_89249ee8bad14df883d26fc097d77eaf","type":"UnitTestResult","parentId":"wrk_a528e60334a54420a7b384bae215ad1b","modified":1694436101914,"created":1694436101914,"results":{"stats":{"suites":1,"tests":1,"passes":0,"pending":0,"failures":1,"start":{"$$date":1694436101899},"end":{"$$date":1694436101914},"duration":15},"tests":[{"title":"Returns 200","fullTitle":"My Suite Returns 200","file":"/var/folders/_7/6ms57pwx6899ftqnx4cxcsf80000gn/T/insomnia-testing/0.5942253207975523-test.ts","duration":14,"currentRetry":0,"err":{"stack":"Error: attempted to output null or undefined value\n at file:///Applications/Insomnia.app/Contents/Resources/app.asar/index-f89f6e08.js:90:20151\n at /Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:2307:5\n at RawTask.call (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4583:19)\n at MutationObserver.flush (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4660:29)","message":"attempted to output null or undefined value","path":"url","location":{"line":1,"column":1},"type":"render","reason":"undefined","multiple":[{"path":"url","location":"[object Object]","type":"render","reason":"undefined","multiple":"Error: attempted to output null or undefined value"}]}}],"pending":[],"failures":[{"title":"Returns 200","fullTitle":"My Suite Returns 200","file":"/var/folders/_7/6ms57pwx6899ftqnx4cxcsf80000gn/T/insomnia-testing/0.5942253207975523-test.ts","duration":14,"currentRetry":0,"err":{"stack":"Error: attempted to output null or undefined value\n at file:///Applications/Insomnia.app/Contents/Resources/app.asar/index-f89f6e08.js:90:20151\n at /Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:2307:5\n at RawTask.call (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4583:19)\n at MutationObserver.flush (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4660:29)","message":"attempted to output null or undefined value","path":"url","location":{"line":1,"column":1},"type":"render","reason":"undefined","multiple":[{"path":"url","location":"[object Object]","type":"render","reason":"undefined","multiple":"Error: attempted to output null or undefined value"}]}}],"passes":[]}}
{"_id":"utr_96caab34bbdd46e8940ab260c53441cd","type":"UnitTestResult","parentId":"wrk_a528e60334a54420a7b384bae215ad1b","modified":1694436103834,"created":1694436103834,"results":{"stats":{"suites":1,"tests":1,"passes":0,"pending":0,"failures":1,"start":{"$$date":1694436103818},"end":{"$$date":1694436103834},"duration":16},"tests":[{"title":"Returns 200","fullTitle":"My Suite Returns 200","file":"/var/folders/_7/6ms57pwx6899ftqnx4cxcsf80000gn/T/insomnia-testing/0.55166761668619-test.ts","duration":14,"currentRetry":0,"err":{"stack":"Error: attempted to output null or undefined value\n at file:///Applications/Insomnia.app/Contents/Resources/app.asar/index-f89f6e08.js:90:20151\n at /Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:2307:5\n at RawTask.call (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4583:19)\n at MutationObserver.flush (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4660:29)","message":"attempted to output null or undefined value","path":"url","location":{"line":1,"column":1},"type":"render","reason":"undefined","multiple":[{"path":"url","location":"[object Object]","type":"render","reason":"undefined","multiple":"Error: attempted to output null or undefined value"}]}}],"pending":[],"failures":[{"title":"Returns 200","fullTitle":"My Suite Returns 200","file":"/var/folders/_7/6ms57pwx6899ftqnx4cxcsf80000gn/T/insomnia-testing/0.55166761668619-test.ts","duration":14,"currentRetry":0,"err":{"stack":"Error: attempted to output null or undefined value\n at file:///Applications/Insomnia.app/Contents/Resources/app.asar/index-f89f6e08.js:90:20151\n at /Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:2307:5\n at RawTask.call (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4583:19)\n at MutationObserver.flush (/Applications/Insomnia.app/Contents/Resources/app.asar/node_modules/nunjucks/browser/nunjucks.js:4660:29)","message":"attempted to output null or undefined value","path":"url","location":{"line":1,"column":1},"type":"render","reason":"undefined","multiple":[{"path":"url","location":"[object Object]","type":"render","reason":"undefined","multiple":"Error: attempted to output null or undefined value"}]}}],"passes":[]}}
@@ -0,0 +1,3 @@
{"_id":"uts_6d26df3191ab46a08fe2e5859754e1cf","type":"UnitTestSuite","parentId":"wrk_1b49626a0a9442b7b9474a1f3493bb5d","modified":1694513741703,"created":1694513741703,"name":"New Suite"}
{"_id":"uts_aeb27e8dade847ab89f53cab2c0eafbc","type":"UnitTestSuite","parentId":"wrk_a528e60334a54420a7b384bae215ad1b","modified":1694436073148,"created":1694436073148,"name":"Test Open API"}
{"_id":"uts_c547332ddcda43ca8e47b489519b170f","type":"UnitTestSuite","parentId":"wrk_55a8240d025044d3a40eb40956126bec","modified":1694513485323,"created":1694513485323,"name":"New Suite"}
@@ -0,0 +1,8 @@
{"_id":"wrk_1b49626a0a9442b7b9474a1f3493bb5d","type":"Workspace","parentId":"proj_team_195a6ce0edb1427eb2e8ba7b986072e4","modified":1694513770541,"created":1694513741451,"name":"Remote Design Document","description":"","scope":"design"}
{"_id":"wrk_3f71ff5dcf5343169b9a67236f9deafe","type":"Workspace","parentId":"proj_team_195a6ce0edb1427eb2e8ba7b986072e4","modified":1694513800004,"created":1694513691424,"name":"(GIT) Remote Collection","description":"","scope":"collection"}
{"_id":"wrk_55a8240d025044d3a40eb40956126bec","type":"Workspace","parentId":"proj_team_195a6ce0edb1427eb2e8ba7b986072e4","modified":1694513791914,"created":1694513468782,"name":"(GIT) Remote Design Document","description":"","scope":"design"}
{"_id":"wrk_7c9f917b97cb4a43bb402ace6df1b107","type":"Workspace","parentId":"proj_f5359773e8b544c2bfeec86c95b978dc","modified":1694513877548,"created":1694513835041,"name":"Local Collection","description":"","scope":"collection"}
{"_id":"wrk_a528e60334a54420a7b384bae215ad1b","type":"Workspace","parentId":"proj_f5359773e8b544c2bfeec86c95b978dc","modified":1694436050037,"created":1694436050037,"name":"OpenAPI","description":"","scope":"design"}
{"_id":"wrk_d783eca2fa46457c9f02a221ec862458","type":"Workspace","parentId":"proj_default-project","modified":1694513890770,"created":1694513890770,"name":"Local Design Document","description":"","scope":"design"}
{"_id":"wrk_ef815fde95ce489aa225fc4408a04bf7","type":"Workspace","parentId":"proj_team_195a6ce0edb1427eb2e8ba7b986072e4","modified":1694513499173,"created":1628147455076,"name":"Remote Collection","description":"","scope":"collection"}
{"_id":"wrk_f3246c005c9d48ed9e35724415c962d6","type":"Workspace","parentId":"proj_default-project","modified":1694513902250,"created":1694435944027,"name":"Local Collection","description":"","scope":"collection"}
@@ -0,0 +1,8 @@
{"_id":"wrkm_058529e2e6f541d4b58f4beebc0c8dbe","type":"WorkspaceMeta","parentId":"wrk_3f71ff5dcf5343169b9a67236f9deafe","modified":1694513700703,"created":1694513691444,"activeActivity":null,"activeEnvironmentId":null,"activeRequestId":null,"activeUnitTestSuiteId":null,"cachedGitLastAuthor":null,"cachedGitLastCommitTime":null,"cachedGitRepositoryBranch":null,"gitRepositoryId":"git_a02b558275414a518e6107c3e85e405a","hasSeen":true,"paneHeight":0.5,"paneWidth":0.5,"sidebarFilter":"","sidebarHidden":false,"sidebarWidth":19,"pushSnapshotOnInitialize":false}
{"_id":"wrkm_13722a5db6a34919b78af1b167674ef0","type":"WorkspaceMeta","parentId":"wrk_1b49626a0a9442b7b9474a1f3493bb5d","modified":1694513743823,"created":1694513741737,"activeActivity":null,"activeEnvironmentId":null,"activeRequestId":null,"activeUnitTestSuiteId":null,"cachedGitLastAuthor":null,"cachedGitLastCommitTime":null,"cachedGitRepositoryBranch":null,"gitRepositoryId":null,"hasSeen":true,"paneHeight":0.5,"paneWidth":0.5,"sidebarFilter":"","sidebarHidden":false,"sidebarWidth":19,"pushSnapshotOnInitialize":false}
{"_id":"wrkm_3a87a51a288d428786650a91deeb507e","type":"WorkspaceMeta","parentId":"wrk_f3246c005c9d48ed9e35724415c962d6","modified":1694513620993,"created":1694435944035,"activeActivity":null,"activeEnvironmentId":"env_ae8fb881d7f14abbb60c27c82dcf6072","activeRequestId":"req_3049c3a7c24245c986b29e80ad5a44c6","activeUnitTestSuiteId":null,"cachedGitLastAuthor":null,"cachedGitLastCommitTime":null,"cachedGitRepositoryBranch":null,"gitRepositoryId":null,"hasSeen":true,"paneHeight":0.5,"paneWidth":0.5,"sidebarFilter":"","sidebarHidden":false,"sidebarWidth":19,"pushSnapshotOnInitialize":false}
{"_id":"wrkm_6d6bed9b0a464bc2a1fcdf0c1a137538","type":"WorkspaceMeta","parentId":"wrk_55a8240d025044d3a40eb40956126bec","modified":1694513651760,"created":1694513468824,"activeActivity":null,"activeEnvironmentId":null,"activeRequestId":null,"activeUnitTestSuiteId":"uts_c547332ddcda43ca8e47b489519b170f","cachedGitLastAuthor":null,"cachedGitLastCommitTime":null,"cachedGitRepositoryBranch":null,"gitRepositoryId":"git_82bf4ce708514ba4a61e5a23a644e0d7","hasSeen":true,"paneHeight":0.5,"paneWidth":0.5,"sidebarFilter":"","sidebarHidden":false,"sidebarWidth":19,"pushSnapshotOnInitialize":false}
{"_id":"wrkm_9675fa52fcb544bd9b9f383ae2bfcc5d","type":"WorkspaceMeta","parentId":"wrk_ef815fde95ce489aa225fc4408a04bf7","modified":1694513669920,"created":1694436238621,"activeActivity":null,"activeEnvironmentId":null,"activeRequestId":"req_dbd2fe72a91946359532fbff416f25d7","activeUnitTestSuiteId":null,"cachedGitLastAuthor":null,"cachedGitLastCommitTime":null,"cachedGitRepositoryBranch":null,"gitRepositoryId":null,"hasSeen":true,"paneHeight":0.5,"paneWidth":0.5,"sidebarFilter":"","sidebarHidden":false,"sidebarWidth":19,"pushSnapshotOnInitialize":false}
{"_id":"wrkm_b7225af0fbe347568acadd18904389ee","type":"WorkspaceMeta","parentId":"wrk_7c9f917b97cb4a43bb402ace6df1b107","modified":1694513851556,"created":1694513835065,"activeActivity":null,"activeEnvironmentId":null,"activeRequestId":null,"activeUnitTestSuiteId":null,"cachedGitLastAuthor":null,"cachedGitLastCommitTime":null,"cachedGitRepositoryBranch":null,"gitRepositoryId":"git_da0217efdd80460faa2f153c1e871083","hasSeen":true,"paneHeight":0.5,"paneWidth":0.5,"sidebarFilter":"","sidebarHidden":false,"sidebarWidth":19,"pushSnapshotOnInitialize":false}
{"_id":"wrkm_ede333e3b385412fbdce7e4b5e2d1695","type":"WorkspaceMeta","parentId":"wrk_a528e60334a54420a7b384bae215ad1b","modified":1694513822919,"created":1694436050046,"activeActivity":null,"activeEnvironmentId":"env_05e568304a74414b8b19bec3bae0e38d","activeRequestId":"req_163e848a55f94c8096d53a70d5ca6ef9","activeUnitTestSuiteId":"uts_aeb27e8dade847ab89f53cab2c0eafbc","cachedGitLastAuthor":null,"cachedGitLastCommitTime":null,"cachedGitRepositoryBranch":null,"gitRepositoryId":"git_1fded700bfb74aa483560e116866d25e","hasSeen":true,"paneHeight":0.5,"paneWidth":0.5,"sidebarFilter":"","sidebarHidden":false,"sidebarWidth":19,"pushSnapshotOnInitialize":false}
{"_id":"wrkm_f305f30c0eea4bfbb81ecbf3f00887e8","type":"WorkspaceMeta","parentId":"wrk_d783eca2fa46457c9f02a221ec862458","modified":1694513890794,"created":1694513890794,"activeActivity":null,"activeEnvironmentId":null,"activeRequestId":null,"activeUnitTestSuiteId":null,"cachedGitLastAuthor":null,"cachedGitLastCommitTime":null,"cachedGitRepositoryBranch":null,"gitRepositoryId":null,"hasSeen":true,"paneHeight":0.5,"paneWidth":0.5,"sidebarFilter":"","sidebarHidden":false,"sidebarWidth":19,"pushSnapshotOnInitialize":false}
@@ -20,6 +20,12 @@ const config: PlaywrightTestConfig = {
testMatch: /critical\/.*.test.ts/,
retries: 0,
},
{
// Single critical path test, runs on release recurring
name: 'Migration',
testMatch: /migration\/.*.test.ts/,
retries: 0,
},
],
webServer: {
command: 'npm run serve',
@@ -12,6 +12,16 @@ export const loadFixture = async (fixturePath: string) => {
return buffer.toString('utf-8');
};
export const copyFixtureDatabase = async (fixturePath: string, dataPath: string) => {
const fixtureDir = path.join(__dirname, '..', 'fixtures', fixturePath);
if (!fs.existsSync(fixtureDir)) {
throw new Error(`Cannot find fixture directory ${fixtureDir}`);
}
await fs.promises.cp(fixtureDir, dataPath, { recursive: true });
};
export const randomDataPath = () => path.join(os.tmpdir(), 'insomnia-smoke-test', `${uuidv4()}`);
export const INSOMNIA_DATA_PATH = randomDataPath();
@@ -14,24 +14,53 @@ interface EnvOptions {
INSOMNIA_DATA_PATH: string;
INSOMNIA_API_URL: string;
INSOMNIA_APP_WEBSITE_URL: string;
INSOMNIA_AI_URL: string;
INSOMNIA_GITHUB_API_URL: string;
INSOMNIA_GITLAB_API_URL: string;
INSOMNIA_UPDATES_URL: string;
INSOMNIA_SKIP_ONBOARDING: string;
INSOMNIA_PUBLIC_KEY: string;
INSOMNIA_SECRET_KEY: string;
INSOMNIA_SESSION?: string;
}
export const test = baseTest.extend<{
app: ElectronApplication;
dataPath: string;
fixturesPath: string;
userConfig: {
skipOnboarding: boolean;
publicKey: string;
secretKey: string;
code: string;
session?: {
accountId: string;
id: string;
sessionExpiry: Date;
email: string;
firstName: string;
lastName: string;
symmetricKey: string;
publicKey: string;
encPrivateKey: string;
};
};
}>({
app: async ({ playwright, trace }, use, testInfo) => {
app: async ({ playwright, trace, dataPath, userConfig }, use, testInfo) => {
const webServerUrl = testInfo.config.webServer?.url;
const options: EnvOptions = {
INSOMNIA_DATA_PATH: randomDataPath(),
INSOMNIA_DATA_PATH: dataPath,
INSOMNIA_API_URL: webServerUrl + '/api',
INSOMNIA_APP_WEBSITE_URL: webServerUrl + '/website',
INSOMNIA_AI_URL: webServerUrl + '/ai',
INSOMNIA_GITHUB_API_URL: webServerUrl + '/github-api/graphql',
INSOMNIA_GITLAB_API_URL: webServerUrl + '/gitlab-api',
INSOMNIA_UPDATES_URL: webServerUrl || 'https://updates.insomnia.rest',
INSOMNIA_SKIP_ONBOARDING: String(userConfig.skipOnboarding),
INSOMNIA_PUBLIC_KEY: userConfig.publicKey,
INSOMNIA_SECRET_KEY: userConfig.secretKey,
...userConfig.session ? { INSOMNIA_SESSION: JSON.stringify(userConfig.session) } : {},
};
const electronApp = await playwright._electron.launch({
@@ -46,6 +75,7 @@ export const test = baseTest.extend<{
});
const appContext = electronApp.context();
const traceMode: TraceMode = typeof trace === 'string' ? trace as TraceMode : trace.mode;
const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true };
@@ -73,4 +103,29 @@ export const test = baseTest.extend<{
await use(page);
},
dataPath: async ({ }, use) => {
const insomniaDataPath = randomDataPath();
await use(insomniaDataPath);
},
userConfig: async ({ }, use) => {
await use({
skipOnboarding: true,
publicKey: 'txb/w8DASTpPQqeHE/hpI3ABKzit+pv5n2We5dbtYRo=',
secretKey: 'Tb1QKsI3wVZxhS8TuQESHB2x7f68PzeTzTMmLpnnFVU=',
code: 'BTxpIfgXY1VgUpoPpqA25RkCPGQ2MAkZsaY6IZ0bamd0WsYQlJM6iy8PV9hEHS1Gk96SBC6%2BM%2FGhv8IaVl1N6V5wdghHwU2sGKGkW%2Fevx1HiqAUsAqIry8aWRqAkc0n3KmW%2B%2F8lyeHCpy5jhsXqMMqXMbZh8dN1q%2ByRe2C6MJS1A706KbPUhI7PRi%2FsmK0TcNT7lgBKKHRVzPTvjpLcjgzSJFL4K%2BEzgY9Ue4gh0gPw89sM9dV%2F2sAlpw0LA7rF06NyoPhA%3D',
session: {
'id': 'sess_64a477e6b59d43a5a607f84b4f73e3ce',
// Expire in 2077
'sessionExpiry': new Date(2147483647000),
'publicKey': "{ 'alg': 'RSA-OAEP-256', 'e': 'AQAB', 'ext': true, 'key_ops': ['encrypt'], 'kty': 'RSA', 'n': 'pTQVaUaiqggIldSKm6ib6eFRLLoGj9W-2O4gTbiorR-2b8-ZmKUwQ0F-jgYX71AjYaFn5VjOHOHSP6byNAjN7WzJ6A_Z3tytNraLoZfwK8KdfflOCZiZzQeD3nO8BNgh_zEgCHStU61b6N6bSpCKjbyPkmZcOkJfsz0LJMAxrXvFB-I42WYA2vJKReTJKXeYx4d6L_XGNIoYtmGZit8FldT4AucfQUXgdlKvr4_OZmt6hgjwt_Pjcu-_jO7m589mMWMebfUhjte3Lp1jps0MqTOvgRb0FQf5eoBHnL01OZjvFPDKeqlvoz7II9wFNHIKzSvgAKnyemh6DiyPuIukyQ' }",
'encPrivateKey': "{ 'iv': '4a09fba2c412d7ea205b6168', 't': 'a4fa1a524e89e668444de654f1bd1ba8', 'd': 'b695b6ec7d41327b723e395b3788cc08c89dcf7b4db0811c3e91af4aa9ed1c9cb8132b591fe24498ffcc48c0055c1c0985a48d9e96962961c049cea508b6c38e83dfc831a4b1a82ad3e79a26d6ed3c1c9b73043a0e266cfe6eac661a75f4b9862afe2a81362d640bb2fdb6d0015204d04c322f1cb7f33faa593b538b58bda75b0c5e56583d5a55eea89e74d96ce29d862614414ee298f56105ea3dbc479aea9330618ba3e94efe874b33cd99954b12f27d7ff9e7f981310381fa0b3f1a05fbac71862ecc67ddbf7062f718d1d8bbf03f35afc3a8b1b36b177f278ab8dd12c14c862bca52a2c63bca05c7fc9bd8f1000ddc328ad1b5a72b96f110c3443294129db416bd385d19c73a1b342b4887feffa17639cc96b7b7154903c2de183f73d3116d98c8d32ea8b9627d0a5200da98d28c89c34008d4e6fa4cfbd7e1b7e1f36cfec6d0020b306c7def8d24c6091252764bde2eef74f35bdaa605dc27fcd302d179fcf65d6c7d18d3dd36cf6380bd40a29198a0398a6cb1ab79a71be00f7783b6559a146f1f825d25a990162e923e2dbfdd1ee868c8b63844f9394415ebab9f397c8d78608de00369728744b8344724e5c2f1e4ba95522406bd7042fc271793af32bfa1c2724defc8a88185cc5c2825c0453fcb39dc5ac9147d3ba60006fccca855678521da06b426dfd04333511b7d8184a8960dadefb1ef89f5fa648304adcd79734fea763f7dbd0c2788c64ea302f8e33602ab041aec619661167b2f167a4b2cadc6b7cf0c22867fcdd73528fb5585b9d13f6d90ab36c5ef231bd4f2464650e541e6dead1753487b45a8ade3fe46e2327fd0e32d8adafd4e1d2ffcb2df1ed50718d0d29829f8bf4bc33da524640388b0cb9f640b70f9ef0a1d073bc80abdf975fe77b35f07aee5135e2924661d26e5d299a432c563a3bbc5ff21d1fde07ff2336b32b17067c01adc6697568aabf3ff4882530763f77d96cef2fcc7336e3f8e4a2b8de5df42aaeaeccd9e3681604e677fad555148ced6057d99cab03389bb566b27cc4ea3946a640f05593e5944c74adf5d0649941b8032dc6959bdef917fd7d2da3139b1d3770d411b52752c9299f789ce5de64e802740a8210e1c70e0ffb8aa45a3647b837e2c5d1a7dd676b238268ac7c060bcc771285f21a283c2f0eefb54254086770a4f09140f7b6a118a7df1e06445379080c2cb6a8840b9d70411521107b47751634e3ff6437974ac2e5897e7e15ac8bdbb5325bb1dd09c20f8ac37fa1eaf2765671fd1434460cbf3cc97bf67b19f88b2bfbde99836c27c338b7f19fc20aad90b91e268c87b81aa17026ac5ac74f47c3525fd2d0d584d3b1d75dd360f105f78b2831481802b6a40e88938660d1598947ffb4e7cf75cd67308d6f910be2fb9beafb68d5ea7c3d2f79c3b66223d610a70a6f9ce3c3447bc0acf74e84687c2da5a137b6c14631971e19133a61bfa94c247ae99d771d8efc11d983e2ea904dab4ca479fa00be3b0372e100225311ffb5b95faed4c32b5794cc618ded1027e6f2a54328a5cd322da6c6ef91151cacfa456680547adf18cde5323869bc03b2c7edd731f5e5c9b9eaa7b2f57d4246d324047482a48d7472650b8d0614a0e133e849a09d37bc9f7921d05397b98e398cd3411dde80d9bd6be4384289a2d1a0416cd914e7520cae962493d31b652a520a9fca7d7e6e9e5df53d719e518125b73ea49af30b720a6d0a71089dcaf04da9ee05c4ede6d0ba376c86282293248a4b36a2ac07a3297d569ad4e958c918317a4d526dae47b07f8c6615a77f5831d146c063b88246e2b3ce7b8f4b75291c339c317e3fbc84563694cd749f021b1e0c076521d685f87497831f19cba89601a344c5d1d08f12b2de9d5d068daf760bf87993e89a2912ab29e3fc79af39db18e982bfe0ee0374c84487cabc1f59bc216d71c38654805cddbc338fc8c14413849ea3ef79444ac6078fb2403ecd84de5b678538be0b2580ecb1926e03643ff29464f943cd729ad386daf1f81ea385e79260cdf78d579281adb72946692d54e94a2fd8530dfb8e5923ce642ec92ccee28f6b21efdff24ec820b4eff26f493278acb485af055881e077cdf3017bc6104b2394fee39343b7c71c20cbf7a3ea96b0c7b603a2ff998d27b16833b028bf30ab668041c8d82225d58bd95f9246de742815067046adbf55eddfddfbc30fea3b8c6659d2756c702f2012395245035bf5338427051b4eb392225aa10179d8b042ba77bc1a37cd66a655ec03aa3aa3c75e05aad4ad38240ee0e6c5af85bc7813f2c0de6eccf5cfba2f6295daf448c042c50c6eba6127f170848cc2034bd61698747a3bee155146d2ab73ba79d969cffcba737bd85b20123a5e3080edba483d831c38c9a4aee9a2fdeb0819665cf28aab91f2317f77d22b29f49d6dbd4ae5b82f9529fb208824f22fdd48666dfc0abe4a9d00dd7d552f4bf6fade29b63ad080614bfe04d9fdca7cff96378e201f6e71cc665e6ae8abd64d125a8c222b03f9153824251db960b4eae41280b681a9fa6c1ec76e94bcd9656aa3df3b57f2da9', 'ad': '' }",
'symmetricKey': "{ 'iv': '0146bfcc7b89a3aa055bedae', 't': '7559a4ef7ca495c9605516cc846007a3', 'd': '4de3ab37e73dd6fc294257fe4cb1af26229434297ecdd309e93a941bd1f9913b5916dfe55d62f0d4015c46f66d8fdf4c84ab88c22e4d24428d5fe6c1affce1e14b33760a382b67b4a37262f9ca5a44cb9760b151bbd0748fc18f8f438545df356d99a66c74ff22b623b2b67d9765f80ac6f18af01684e6e3efbce947832ac0bea010c1cde00390e1f3d2187286ff00a43aef8ddc13a98d8f4f771bba1694712623b115f0b2c0e891eccd074ade0b551737b915d0f1242ffcbc1c65555ff7', 'ad': '' }",
'email': 'insomnia-user@konghq.com',
'accountId': 'acct_64a477e6b59d43a5a607f84b4f73e3ce',
'firstName': 'Rick',
'lastName': 'Morty',
},
});
},
});
@@ -11,6 +11,7 @@ import githubApi from './github-api';
import gitlabApi from './gitlab-api';
import { schema } from './graphql';
import { startGRPCServer } from './grpc';
import insomniaApi from './insomnia-api';
import { oauthRoutes } from './oauth';
import { startWebSocketServer } from './websocket';
@@ -47,6 +48,7 @@ app.use('/auth/basic', basicAuthRouter);
githubApi(app);
gitlabApi(app);
insomniaApi(app);
app.get('/delay/seconds/:duration', (req, res) => {
const delaySec = Number.parseInt(req.params.duration || '2');
@@ -0,0 +1,208 @@
import { randomUUID } from 'crypto';
import type { Application } from 'express';
import { json } from 'express';
const currentPlan = {
isActive: true,
period: 'year',
planId: 'team',
price: 100,
quantity: 10,
type: 'team',
};
const projectsByOrgId = new Map(Object.entries({
'org_7ef19d06-5a24-47ca-bc81-3dea011edec2': [
{
id: 'proj_org_7ef19d06-5a24-47ca-bc81-3dea011edec2',
name: 'Personal Workspace',
},
],
'team_195a6ce0edb1427eb2e8ba7b986072e4': [
{
id: 'proj_team_195a6ce0edb1427eb2e8ba7b986072e4',
name: 'Personal Workspace',
},
],
}));
const organizations = [
// Personal organization
{
'id': 'org_7ef19d06-5a24-47ca-bc81-3dea011edec2',
'name': 'feb56ab4b19347c4b648c99bfa7db363',
'display_name': 'Personal workspace',
'branding': {
'logo_url': '',
},
'metadata': {
'organizationType': 'personal',
'ownerAccountId': 'acct_64a477e6b59d43a5a607f84b4f73e3ce',
},
},
// Team Organization: Was a team before the migration now looks like this:
// Teams migrated to Organizations have an id that starts with team_ and the team id is the same as the organization id
{
'id': 'team_195a6ce0edb1427eb2e8ba7b986072e4',
'name': '07df6d95b60e4593af0424c74d96637a-team',
'display_name': '🦄 Magic',
'branding': {
'logo_url': '',
},
'metadata': {
'organizationType': 'team',
'ownerAccountId': 'acct_64a477e6b59d43a5a607f84b4f73e3ce',
},
},
];
const organizationFeatures = {
features: {
gitSync: {
enabled: true,
},
},
};
const user = {
'id': 'email|64f0dd619ab0786da330d83a',
'email': 'insomnia-user@konghq.com',
'name': 'Rick Morty',
'picture': '',
'bio': 'My BIO',
'github': '',
'linkedin': '',
'twitter': '',
'identities': null,
'given_name': '',
'family_name': '',
};
const whoami = {
'sessionExpiry': 4838400,
'publicKey': '{"alg":"RSA-OAEP-256","e":"AQAB","ext":true,"key_ops":["encrypt"],"kty":"RSA","n":"pTQVaUaiqggIldSKm6ib6eFRLLoGj9W-2O4gTbiorR-2b8-ZmKUwQ0F-jgYX71AjYaFn5VjOHOHSP6byNAjN7WzJ6A_Z3tytNraLoZfwK8KdfflOCZiZzQeD3nO8BNgh_zEgCHStU61b6N6bSpCKjbyPkmZcOkJfsz0LJMAxrXvFB-I42WYA2vJKReTJKXeYx4d6L_XGNIoYtmGZit8FldT4AucfQUXgdlKvr4_OZmt6hgjwt_Pjcu-_jO7m589mMWMebfUhjte3Lp1jps0MqTOvgRb0FQf5eoBHnL01OZjvFPDKeqlvoz7II9wFNHIKzSvgAKnyemh6DiyPuIukyQ"}',
'encPrivateKey': '{"iv":"4a09fba2c412d7ea205b6168","t":"a4fa1a524e89e668444de654f1bd1ba8","d":"b695b6ec7d41327b723e395b3788cc08c89dcf7b4db0811c3e91af4aa9ed1c9cb8132b591fe24498ffcc48c0055c1c0985a48d9e96962961c049cea508b6c38e83dfc831a4b1a82ad3e79a26d6ed3c1c9b73043a0e266cfe6eac661a75f4b9862afe2a81362d640bb2fdb6d0015204d04c322f1cb7f33faa593b538b58bda75b0c5e56583d5a55eea89e74d96ce29d862614414ee298f56105ea3dbc479aea9330618ba3e94efe874b33cd99954b12f27d7ff9e7f981310381fa0b3f1a05fbac71862ecc67ddbf7062f718d1d8bbf03f35afc3a8b1b36b177f278ab8dd12c14c862bca52a2c63bca05c7fc9bd8f1000ddc328ad1b5a72b96f110c3443294129db416bd385d19c73a1b342b4887feffa17639cc96b7b7154903c2de183f73d3116d98c8d32ea8b9627d0a5200da98d28c89c34008d4e6fa4cfbd7e1b7e1f36cfec6d0020b306c7def8d24c6091252764bde2eef74f35bdaa605dc27fcd302d179fcf65d6c7d18d3dd36cf6380bd40a29198a0398a6cb1ab79a71be00f7783b6559a146f1f825d25a990162e923e2dbfdd1ee868c8b63844f9394415ebab9f397c8d78608de00369728744b8344724e5c2f1e4ba95522406bd7042fc271793af32bfa1c2724defc8a88185cc5c2825c0453fcb39dc5ac9147d3ba60006fccca855678521da06b426dfd04333511b7d8184a8960dadefb1ef89f5fa648304adcd79734fea763f7dbd0c2788c64ea302f8e33602ab041aec619661167b2f167a4b2cadc6b7cf0c22867fcdd73528fb5585b9d13f6d90ab36c5ef231bd4f2464650e541e6dead1753487b45a8ade3fe46e2327fd0e32d8adafd4e1d2ffcb2df1ed50718d0d29829f8bf4bc33da524640388b0cb9f640b70f9ef0a1d073bc80abdf975fe77b35f07aee5135e2924661d26e5d299a432c563a3bbc5ff21d1fde07ff2336b32b17067c01adc6697568aabf3ff4882530763f77d96cef2fcc7336e3f8e4a2b8de5df42aaeaeccd9e3681604e677fad555148ced6057d99cab03389bb566b27cc4ea3946a640f05593e5944c74adf5d0649941b8032dc6959bdef917fd7d2da3139b1d3770d411b52752c9299f789ce5de64e802740a8210e1c70e0ffb8aa45a3647b837e2c5d1a7dd676b238268ac7c060bcc771285f21a283c2f0eefb54254086770a4f09140f7b6a118a7df1e06445379080c2cb6a8840b9d70411521107b47751634e3ff6437974ac2e5897e7e15ac8bdbb5325bb1dd09c20f8ac37fa1eaf2765671fd1434460cbf3cc97bf67b19f88b2bfbde99836c27c338b7f19fc20aad90b91e268c87b81aa17026ac5ac74f47c3525fd2d0d584d3b1d75dd360f105f78b2831481802b6a40e88938660d1598947ffb4e7cf75cd67308d6f910be2fb9beafb68d5ea7c3d2f79c3b66223d610a70a6f9ce3c3447bc0acf74e84687c2da5a137b6c14631971e19133a61bfa94c247ae99d771d8efc11d983e2ea904dab4ca479fa00be3b0372e100225311ffb5b95faed4c32b5794cc618ded1027e6f2a54328a5cd322da6c6ef91151cacfa456680547adf18cde5323869bc03b2c7edd731f5e5c9b9eaa7b2f57d4246d324047482a48d7472650b8d0614a0e133e849a09d37bc9f7921d05397b98e398cd3411dde80d9bd6be4384289a2d1a0416cd914e7520cae962493d31b652a520a9fca7d7e6e9e5df53d719e518125b73ea49af30b720a6d0a71089dcaf04da9ee05c4ede6d0ba376c86282293248a4b36a2ac07a3297d569ad4e958c918317a4d526dae47b07f8c6615a77f5831d146c063b88246e2b3ce7b8f4b75291c339c317e3fbc84563694cd749f021b1e0c076521d685f87497831f19cba89601a344c5d1d08f12b2de9d5d068daf760bf87993e89a2912ab29e3fc79af39db18e982bfe0ee0374c84487cabc1f59bc216d71c38654805cddbc338fc8c14413849ea3ef79444ac6078fb2403ecd84de5b678538be0b2580ecb1926e03643ff29464f943cd729ad386daf1f81ea385e79260cdf78d579281adb72946692d54e94a2fd8530dfb8e5923ce642ec92ccee28f6b21efdff24ec820b4eff26f493278acb485af055881e077cdf3017bc6104b2394fee39343b7c71c20cbf7a3ea96b0c7b603a2ff998d27b16833b028bf30ab668041c8d82225d58bd95f9246de742815067046adbf55eddfddfbc30fea3b8c6659d2756c702f2012395245035bf5338427051b4eb392225aa10179d8b042ba77bc1a37cd66a655ec03aa3aa3c75e05aad4ad38240ee0e6c5af85bc7813f2c0de6eccf5cfba2f6295daf448c042c50c6eba6127f170848cc2034bd61698747a3bee155146d2ab73ba79d969cffcba737bd85b20123a5e3080edba483d831c38c9a4aee9a2fdeb0819665cf28aab91f2317f77d22b29f49d6dbd4ae5b82f9529fb208824f22fdd48666dfc0abe4a9d00dd7d552f4bf6fade29b63ad080614bfe04d9fdca7cff96378e201f6e71cc665e6ae8abd64d125a8c222b03f9153824251db960b4eae41280b681a9fa6c1ec76e94bcd9656aa3df3b57f2da9","ad":""}',
'encSymmetricKey': '{"iv":"0146bfcc7b89a3aa055bedae","t":"7559a4ef7ca495c9605516cc846007a3","d":"4de3ab37e73dd6fc294257fe4cb1af26229434297ecdd309e93a941bd1f9913b5916dfe55d62f0d4015c46f66d8fdf4c84ab88c22e4d24428d5fe6c1affce1e14b33760a382b67b4a37262f9ca5a44cb9760b151bbd0748fc18f8f438545df356d99a66c74ff22b623b2b67d9765f80ac6f18af01684e6e3efbce947832ac0bea010c1cde00390e1f3d2187286ff00a43aef8ddc13a98d8f4f771bba1694712623b115f0b2c0e891eccd074ade0b551737b915d0f1242ffcbc1c65555ff7","ad":""}',
'email': 'insomnia-user@konghq.com',
'accountId': 'acct_64a477e6b59d43a5a607f84b4f73e3ce',
'firstName': 'Rick',
'lastName': 'Morty',
};
export default (app: Application) => {
app.post('/api/graphql', json(), (_req, res) => {
res.status(200).send({
data: {
viewer: {
name: 'InsomniaUser',
email: 'sleepyhead@email.com',
},
},
});
});
// User
app.get('/api/v1/user/profile', (_req, res) => {
console.log('GET *');
res.status(200).send(user);
});
app.get('/api/auth/whoami', (_req, res) => {
res.status(200).send(whoami);
});
// Billing
app.get('/api/v1/billing/current-plan', json(), (_req, res) => {
res.status(200).send(currentPlan);
});
// Organizations
app.get('/api/v1/organizations', (_req, res) => {
res.status(200).send({
organizations: organizations,
});
});
app.get('/api/v1/organizations/:orgId/features', (_req, res) => {
res.status(200).send(organizationFeatures);
});
// Projects
app.get('/api/v1/organizations/:orgId/team-projects', (_req, res) => {
res.status(200).send({
data: projectsByOrgId.get(_req.params.orgId),
});
});
app.delete('/api/v1/organizations/:orgId/team-projects/:projectId', json(), (_req, res) => {
const projects = projectsByOrgId.get(_req.params.orgId)?.filter(project => project.id !== _req.params.projectId);
if (!projects) {
res.status(500).send();
return;
}
projectsByOrgId.set(_req.params.orgId, projects);
res.status(200).send();
});
app.patch('/api/v1/organizations/:orgId/team-projects/:projectId', json(), (_req, res) => {
const updatedProjects = projectsByOrgId.get(_req.params.orgId)?.map(project => {
if (project.id === _req.params.projectId) {
return {
...project,
name: _req.body.name,
};
}
return project;
});
updatedProjects && projectsByOrgId.set(_req.params.orgId, updatedProjects);
res.status(200).send();
});
app.post('/api/v1/organizations/:organizationId/team-projects', json(), (_req, res) => {
const { organizationId } = _req.params;
if (organizationId === 'personal') {
const personalOrg = organizations.find(org => org.metadata.organizationType === 'personal');
if (!personalOrg) {
res.status(500).send();
return;
}
const newProject = {
id: `proj_${randomUUID()}`,
name: _req.body.name,
};
const projects = [
...(projectsByOrgId.get(personalOrg.id) || []),
newProject,
];
projectsByOrgId.set(personalOrg.id, projects);
res.status(200).send({ ...newProject, organizationId: personalOrg.id });
return;
}
const organization = organizations.find(org => org.id === organizationId);
if (!organization) {
res.status(500).send();
return;
}
const newProject = {
id: `proj_${randomUUID()}`,
name: _req.body.name,
};
const projects = [
...(projectsByOrgId.get(organization.id) || []),
newProject,
];
projectsByOrgId.set(organization.id, projects);
res.status(200).send({ ...newProject, organizationId: organization.id });
});
};
@@ -13,7 +13,7 @@ test('can send requests', async ({ app, page }) => {
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('CollectionSmoke testsjust now').click();
@@ -0,0 +1,75 @@
import { copyFixtureDatabase } from '../../playwright/paths';
import { test } from '../../playwright/test';
const testWithLegacyDatabase = test.extend({
dataPath: async ({ dataPath }, use) => {
await copyFixtureDatabase('insomnia-legacy-db', dataPath);
await use(dataPath);
},
userConfig: async ({ userConfig }, use) => {
await use({
...userConfig,
session: undefined,
});
},
});
// tests new cloud project create but not the vcs part as its too complex to stub the gql endpoint
testWithLegacyDatabase('Run data migration to version 8', async ({ page, userConfig }) => {
// Migration takes a while, adding this to avoid test timeout before it ends
test.slow();
await page.getByLabel('Continue with Google').click(),
await page.locator('input[name="code"]').click();
await page.locator('input[name="code"]').fill(userConfig.code);
await page.getByRole('button', { name: 'Log in' }).click();
// Open migrated Project (Local before migration)
await page.getByLabel('Insomnia').click();
// Open migrated local migrated collection that should now have Insomnia Sync
await page.getByLabel('Local Collection').click();
await page.getByLabel('Mars', { exact: true }).click();
await page.getByRole('option', { name: 'Mars' }).click();
await page.getByLabel('Insomnia Sync').isVisible();
await page.getByText('Get list of rockets').click();
await page.getByTestId('project').click();
// Open migrated local migrated collection that should have Git Sync
await page.getByLabel('Local Project (GIT)').click();
await page.getByLabel('OpenAPI').click();
await page.getByText('Delete user').click();
await page.getByLabel('Git Sync').isVisible();
await page.getByTestId('project').click();
await page.getByLabel('Personal Workspace', { exact: true }).click();
// Open Team that is migrated to Organization
await page.getByRole('link', { name: '🦄' }).click();
// Open remote migrated collection that should have Insomnia Sync
await page.getByLabel('Personal Workspace', { exact: true }).click();
await page.getByLabel('Remote Design Document', { exact: true }).click();
await page.getByText('Updated user').click();
await page.getByLabel('Insomnia Sync').isVisible();
await page.getByTestId('project').click();
// Open remote migrated collection that should have GIT Sync
await page.getByLabel('(GIT) Remote Design Document').click();
await page.getByText('Updated user').click();
await page.getByLabel('Git Sync').isVisible();
await page.getByTestId('project').click();
// Open remote migrated collection that should have Insomnia Sync
await page.getByLabel('Remote Collection', { exact: true }).click();
await page.getByText('New Request').click();
await page.getByLabel('Insomnia Sync').isVisible();
await page.getByTestId('project').click();
// Open remote migrated collection that should have Insomnia Sync
await page.getByLabel('Remote Collection', { exact: true }).click();
await page.getByLabel('Insomnia Sync').isVisible();
});
@@ -12,7 +12,7 @@ test.describe('Design interactions', async () => {
const text = await loadFixture('unit-test.yaml');
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('unit-test.yaml').click();
@@ -20,37 +20,27 @@ test.describe('Design interactions', async () => {
await page.click('a:has-text("Test")');
// Run tests and check results
await page.click('#wrapper >> text=Run Tests');
await page.getByLabel('Run all tests').click();
await expect(page.locator('.app')).toContainText('Request A is found');
await expect(page.locator('.app')).toContainText('Request B is not found');
await expect(page.locator('.app')).toContainText('Tests Passed 2/2');
await expect(page.locator('.app')).toContainText('Tests passed');
// Create a new test suite
await page.click('text=New Test Suite');
await page.click('text=Create Suite');
await page.click('button:has-text("New Suite")');
await page.click('text=New test suite');
// Rename test suite
await page.getByRole('button', { name: 'New Suite' }).click();
await page.getByRole('textbox').fill('New Suite 2');
await page.getByRole('textbox').press('Enter');
// Add a new test
await page.locator('text=New Test').nth(1).click();
await page.click('div[role="dialog"] button:has-text("New Test")');
const label = await page.locator('option', { hasText: 'Request A' }).textContent() || '';
await page.locator('select[name="request"]').selectOption({
label,
});
await page.click('#wrapper >> text=Run Tests');
await expect(page.locator('.app')).toContainText('Tests Passed 1/1');
// Rename a test
// TODO(filipe) - add this in another PR
// Rename a test suite
await page.click('button:has-text("Existing Test Suite")');
await page.click('span:has-text("Existing Test Suite")');
await page.locator('text=New TestRun Tests >> input[type="text"]').fill('Renamed');
await page.locator('text=New TestRun Tests >> input[type="text"]').press('Enter');
await page.click('button:has-text("Renamed")');
await page.getByLabel('New test').click();
// Rename test
await page.getByRole('button', { name: 'Returns 200' }).click();
await page.getByRole('textbox').fill('Returns 200 and works');
await page.getByRole('textbox').press('Enter');
await page.getByRole('heading', { name: 'Returns 200 and works' }).click();
// Use autocomplete inside the test code
// TODO(filipe) - add this in another PR
});
@@ -17,7 +17,7 @@ test.describe('gRPC interactions', () => {
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('CollectionPreRelease gRPCjust now').click();
@@ -14,7 +14,7 @@ test.describe('Plugins', async () => {
await page.locator('text=Generate').first().click();
// check if the plugin shows up on the plugin list
await expect(page.locator('.app')).toContainText('insomnia-plugin-demo-example');
await page.getByRole('cell', { name: 'insomnia-plugin-demo-example' }).click();
});
test('Check Declarative Config and Kong Kubernetes config', async ({ page }) => {
@@ -26,8 +26,8 @@ test.describe('Plugins', async () => {
await expect(page.locator('.app')).toContainText('This is a sample server Petstore server');
// Open declarative config
await page.getByTestId('workspace-dropdown').locator('button').click();
await page.getByRole('menuitem', { name: 'Declarative Config (Legacy)' }).click();
await page.getByLabel('Workspace actions').click();
await page.getByRole('menuitemradio', { name: 'Declarative Config (Legacy)' }).click();
// Check for declarative config contents
await page.getByText('_format_version').click();
@@ -21,7 +21,7 @@ test('Check filter responses by environment preference', async ({ app, page }) =
const text = await loadFixture('simple.yaml');
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('Collectionsimplejust now').click();
@@ -15,7 +15,7 @@ test('can send requests', async ({ app, page }) => {
await page.getByRole('button', { name: 'Create in project' }).click();
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
@@ -93,7 +93,7 @@ test('can cancel requests', async ({ app, page }) => {
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('CollectionSmoke testsjust now').click();
@@ -8,7 +8,7 @@ test.describe('Cookie editor', async () => {
const text = await loadFixture('simple.yaml');
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('Collectionsimplejust now').click();
@@ -13,7 +13,7 @@ test.describe('Dashboard', async () => {
// Create new project
await page.getByRole('button', { name: 'Create new Project' }).click();
await page.locator('text=Create').nth(1).click();
await page.getByRole('button', { name: 'Create', exact: true }).click();
// Check empty project
await expect(page.locator('.app')).toContainText('This is an empty project, to get started create your first resource:');
@@ -23,6 +23,7 @@ test.describe('Dashboard', async () => {
await page.getByRole('menuitemradio', { name: 'Settings' }).click();
await page.getByPlaceholder('My Project').click();
await page.getByPlaceholder('My Project').fill('My Project123');
await page.getByRole('button', { name: 'Update' }).click();
// Check that the project name is updated on modal
await expect(page.locator('.app')).toContainText('My Project123');
@@ -34,12 +35,12 @@ test.describe('Dashboard', async () => {
// Delete project
await page.getByRole('row', { name: 'My Project' }).getByRole('button', { name: 'Project Actions' }).click();
await page.getByRole('menuitemradio', { name: 'Settings' }).click();
// Click text=NameActions Delete >> button
await page.click('text=NameActions Delete >> button');
await page.getByRole('button', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'Click to confirm' }).click();
// After deleting project, return to default Insomnia Dashboard
await expect(page.locator('.app')).toContainText('Insomnia');
await expect(page.locator('.app')).toContainText('Personal Workspace');
await expect(page.locator('.app')).not.toContainText('My Project123');
await expect(page.locator('.app')).toContainText('New Document');
await page.getByLabel('All Files (0)').click();
@@ -57,7 +58,7 @@ test.describe('Dashboard', async () => {
const text = await loadFixture('multiple-workspaces.yaml');
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('CollectionSmoke testsjust now').click();
@@ -94,7 +95,7 @@ test.describe('Dashboard', async () => {
// Create new document
await page.getByRole('button', { name: 'Create in project' }).click();
await page.getByRole('menuitemradio', { name: 'Design Document' }).click();
await page.locator('text=Create').nth(1).click();
await page.getByRole('button', { name: 'Create', exact: true }).click();
await page.getByTestId('project').click();
@@ -131,7 +132,7 @@ test.describe('Dashboard', async () => {
// Create new collection
await page.getByRole('button', { name: 'Create in project' }).click();
await page.getByRole('menuitemradio', { name: 'Request Collection' }).click();
await page.locator('text=Create').nth(1).click();
await page.getByRole('button', { name: 'Create', exact: true }).click();
await page.getByTestId('project').click();
@@ -10,7 +10,7 @@ test.describe('Debug-Sidebar', async () => {
const text = await loadFixture('simple.yaml');
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('Collectionsimplejust now').click();
@@ -58,8 +58,8 @@ test.describe('Debug-Sidebar', async () => {
});
test('Open properties of the collection', async ({ page }) => {
await page.getByTestId('workspace-dropdown').locator('button').click();
await page.getByRole('menuitem', { name: 'Settings' }).click();
await page.getByLabel('Workspace actions', { exact: true }).click();
await page.getByRole('menuitemradio', { name: 'Settings' }).click();
await page.getByText('Collection Settings').click();
});
@@ -8,7 +8,7 @@ test.describe('Environment Editor', async () => {
const text = await loadFixture('environments.yaml');
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('Collectionenvironments').click();
@@ -1,6 +1,6 @@
import { test } from '../../playwright/test';
test('Clone from github', async ({ page }) => {
await page.getByRole('button', { name: 'Git Clone' }).click();
await page.getByLabel('Clone git repository').click();
await page.getByRole('tab', { name: ' Git' }).click();
await page.getByPlaceholder('https://github.com/org/repo.git').fill('https://github.com/gatzjames/insomnia-git-example.git');
await page.getByPlaceholder('Name').fill('J');
@@ -13,8 +13,8 @@ test('Clone from github', async ({ page }) => {
test('Sign in with GitHub', async ({ app, page }) => {
await page.getByRole('button', { name: 'New Document' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Create' }).click();
await page.getByRole('button', { name: 'Git Sync' }).click();
await page.getByRole('button', { name: 'Setup Git Sync' }).click();
await page.getByLabel('Insomnia Sync').click();
await page.getByLabel('Setup Git Sync').click();
await page.getByRole('tab', { name: 'Github' }).click();
@@ -14,7 +14,7 @@ test('can render schema and send GraphQL requests', async ({ app, page }) => {
// Import from clipboard
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('CollectionSmoke GraphQLjust now').click();
@@ -51,7 +51,7 @@ test('can send GraphQL requests after editing and prettifying query', async ({ a
const text = await loadFixture('graphql.yaml');
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('CollectionSmoke GraphQLjust now').click();
@@ -16,7 +16,7 @@ test('can send gRPC requests with reflection', async ({ app, page }) => {
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('CollectionPreRelease gRPCjust now').click();
@@ -3,8 +3,8 @@ import { test } from '../../playwright/test';
test('Sign in with Gitlab', async ({ app, page }) => {
await page.getByRole('button', { name: 'New Document' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Create' }).click();
await page.getByRole('button', { name: 'Git Sync' }).click();
await page.getByRole('button', { name: 'Setup Git Sync' }).click();
await page.getByLabel('Insomnia Sync').click();
await page.getByLabel('Setup Git Sync').click();
await page.getByRole('tab', { name: 'GitLab' }).click();
const fakeGitLabOAuthWebFlow = app.evaluate(electron => {
@@ -23,7 +23,7 @@ test('can make oauth2 requests', async ({ app, page }) => {
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('CollectionOAuth Testingjust now').click();
@@ -16,7 +16,7 @@ test('can make websocket connection', async ({ app, page }) => {
await app.evaluate(async ({ clipboard }, text) => clipboard.writeText(text), text);
await page.getByRole('menuitemradio', { name: 'Import' }).click();
await page.getByText('Clipboard').click();
await page.locator('[data-test-id="import-from-clipboard"]').click();
await page.getByRole('button', { name: 'Scan' }).click();
await page.getByRole('dialog').getByRole('button', { name: 'Import' }).click();
await page.getByText('CollectionWebSocketsjust now').click();
+1
View File
@@ -58,6 +58,7 @@
"electron-context-menu": "^3.6.1",
"electron-log": "^4.4.8",
"grpc-reflection-js": "0.3.0",
"gsap": "^3.11.3",
"hawk": "9.0.1",
"hkdf": "^0.0.2",
"hosted-git-info": "5.2.1",
+25 -11
View File
@@ -6,6 +6,7 @@ type LoginCallback = (isLoggedIn: boolean) => void;
export interface WhoamiResponse {
sessionAge: number;
sessionExpiry: number;
accountId: string;
email: string;
firstName: string;
@@ -29,6 +30,7 @@ export interface WhoamiResponse {
export interface SessionData {
accountId: string;
id: string;
sessionExpiry: Date;
email: string;
firstName: string;
lastName: string;
@@ -46,6 +48,7 @@ export function onLoginLogout(loginCallback: LoginCallback) {
export async function absorbKey(sessionId: string, key: string) {
// Get and store some extra info (salts and keys)
const {
sessionExpiry,
publicKey,
encPrivateKey,
encSymmetricKey,
@@ -55,9 +58,13 @@ export async function absorbKey(sessionId: string, key: string) {
lastName,
} = await _whoami(sessionId);
const symmetricKeyStr = crypt.decryptAES(key, JSON.parse(encSymmetricKey));
const sessionExpiryDate = new Date(Date.now() + (sessionExpiry * 1000));
// Store the information for later
setSessionData(
sessionId,
sessionExpiryDate,
accountId,
firstName,
lastName,
@@ -98,7 +105,7 @@ export async function changePasswordWithToken(rawNewPassphrase: string, confirma
const symmetricKey = JSON.stringify(_getSymmetricKey());
const newEncSymmetricKeyJSON = crypt.encryptAES(newSecret, symmetricKey);
const newEncSymmetricKey = JSON.stringify(newEncSymmetricKeyJSON);
return window.main.insomniaFetch({
await window.main.insomniaFetch({
method: 'POST',
path: '/auth/change-password',
data: {
@@ -113,7 +120,7 @@ export async function changePasswordWithToken(rawNewPassphrase: string, confirma
}
export function sendPasswordChangeCode() {
return window.main.insomniaFetch({
window.main.insomniaFetch({
method: 'POST',
path: '/auth/send-password-code',
sessionId: getCurrentSessionId(),
@@ -143,7 +150,19 @@ export function getPrivateKey() {
export function getCurrentSessionId() {
if (window) {
return window.localStorage.getItem('currentSessionId');
const sessionId = window.localStorage.getItem('currentSessionId');
try {
const { sessionExpiry } = JSON.parse(window.localStorage.getItem(_getSessionKey(sessionId)) || '{}');
const isExpired = sessionExpiry && new Date(sessionExpiry).getTime() < Date.now();
if (isExpired) {
console.log('Session has expired', sessionExpiry);
return '';
}
return sessionId;
} catch (e) {
console.log('Error in expiry logic', e);
return '';
}
} else {
return '';
}
@@ -195,6 +214,7 @@ export async function logout() {
/** Set data for the new session and store it encrypted with the sessionId */
export function setSessionData(
id: string,
sessionExpiry: Date,
accountId: string,
firstName: string,
lastName: string,
@@ -205,6 +225,7 @@ export function setSessionData(
) {
const sessionData: SessionData = {
id,
sessionExpiry,
accountId,
symmetricKey,
publicKey,
@@ -219,13 +240,6 @@ export function setSessionData(
window.localStorage.setItem('currentSessionId', id);
return sessionData;
}
export async function listTeams() {
return window.main.insomniaFetch({
method: 'GET',
path: '/api/teams',
sessionId: getCurrentSessionId(),
});
}
// ~~~~~~~~~~~~~~~~ //
// Helper Functions //
@@ -247,7 +261,7 @@ async function _whoami(sessionId: string | null = null): Promise<WhoamiResponse>
}
function _getAuthSalts(email: string) {
return window.main.insomniaFetch({
return window.main.insomniaFetch<{ saltKey: string; saltAuth: string }>({
method: 'POST',
path: '/auth/login-s',
data: { email },
@@ -10,6 +10,7 @@ describe('exportWorkspacesHAR() and exportRequestsHAR()', () => {
beforeEach(async () => {
await globalBeforeEach();
await models.project.all();
await models.settings.getOrCreate();
});
it('exports a single workspace and some requests only as an HTTP Archive', async () => {
@@ -14,6 +14,7 @@ describe('export', () => {
beforeEach(async () => {
await globalBeforeEach();
await models.project.all();
await models.settings.getOrCreate();
});
describe('exportHar()', () => {
@@ -3,8 +3,7 @@ import fs from 'fs';
import path from 'path';
import { globalBeforeEach } from '../../__jest__/before-each';
import { request, requestGroup, workspace } from '../../models';
import { DEFAULT_PROJECT_ID } from '../../models/project';
import { project, request, requestGroup, workspace } from '../../models';
import * as importUtil from '../import';
describe('isApiSpecImport()', () => {
@@ -39,20 +38,22 @@ describe('importRaw()', () => {
const fixturePath = path.join(__dirname, '..', '__fixtures__', 'curl', 'complex-input.sh');
const content = fs.readFileSync(fixturePath, 'utf8').toString();
const projectToImportTo = await project.create();
const scanResult = await importUtil.scanResources({
content,
});
expect(scanResult.type.id).toBe('curl');
expect(scanResult.type?.id).toBe('curl');
expect(scanResult.errors.length).toBe(0);
await importUtil.importResourcesToProject({
projectId: DEFAULT_PROJECT_ID,
projectId: projectToImportTo._id,
});
const workspacesCount = await workspace.count();
const projectWorkspaces = await workspace.findByParentId(
DEFAULT_PROJECT_ID
projectToImportTo._id
);
const curlRequests = await request.findByParentId(projectWorkspaces[0]._id);
@@ -97,21 +98,21 @@ describe('importRaw()', () => {
it('should import a postman collection to a new workspace', async () => {
const fixturePath = path.join(__dirname, '..', '__fixtures__', 'postman', 'aws-signature-auth-v2_0-input.json');
const content = fs.readFileSync(fixturePath, 'utf8').toString();
const projectToImportTo = await project.create();
const scanResult = await importUtil.scanResources({
content,
});
expect(scanResult.type.id).toBe('postman');
expect(scanResult.type?.id).toBe('postman');
expect(scanResult.errors.length).toBe(0);
await importUtil.importResourcesToProject({
projectId: DEFAULT_PROJECT_ID,
projectId: projectToImportTo._id,
});
const workspacesCount = await workspace.count();
const projectWorkspaces = await workspace.findByParentId(
DEFAULT_PROJECT_ID
projectToImportTo._id
);
const requestGroups = await requestGroup.findByParentId(projectWorkspaces[0]._id);
@@ -17,6 +17,7 @@ describe('render tests', () => {
beforeEach(async () => {
await globalBeforeEach();
await models.project.all();
await models.settings.getOrCreate();
envBuilder.reset();
reqGroupBuilder.reset();
});
@@ -5,6 +5,10 @@ import { KeyCombination } from './settings';
const env = process['env'];
// App Stuff
export const getSkipOnboarding = () => env.INSOMNIA_SKIP_ONBOARDING;
export const getInsomniaSession = () => env.INSOMNIA_SESSION;
export const getInsomniaSecretKey = () => env.INSOMNIA_SECRET_KEY;
export const getInsomniaPublicKey = () => env.INSOMNIA_PUBLIC_KEY;
export const getAppVersion = () => version;
export const getProductName = () => appConfig.productName;
export const getAppDefaultTheme = () => appConfig.theme;
@@ -132,6 +136,7 @@ export enum UpdateURL {
// API
export const getApiBaseURL = () => env.INSOMNIA_API_URL || 'https://api.insomnia.rest';
export const getAIServiceURL = () => env.INSOMNIA_AI_URL || 'https://ai.insomnia.rest';
export const getUpdatesBaseURL = () => env.INSOMNIA_UPDATES_URL || 'https://updates.insomnia.rest';
+3 -1
View File
@@ -17,11 +17,12 @@ import { generateId } from './misc';
export interface Query {
_id?: string | SpecificQuery;
parentId?: string | SpecificQuery | null;
remoteId?: string | null;
remoteId?: string | SpecificQuery | null;
plugin?: string;
key?: string;
environmentId?: string | null;
protoFileId?: string;
name?: string | SpecificQuery;
}
type Sort = Record<string, any>;
@@ -35,6 +36,7 @@ export interface SpecificQuery {
$gt?: number;
$in?: string[];
$nin?: string[];
$ne?: string | null;
}
export type ModelQuery<T extends BaseModel> = Partial<Record<keyof T, SpecificQuery>>;
@@ -0,0 +1,226 @@
import { mkdir, writeFile } from 'fs/promises';
import { join } from 'path';
import { apiSpec, cookieJar, environment, grpcRequest, project, protoDirectory, protoFile, request, requestGroup, unitTest, unitTestSuite, webSocketPayload, webSocketRequest, workspace } from '../models';
import { ApiSpec } from '../models/api-spec';
import { CookieJar } from '../models/cookie-jar';
import { Environment } from '../models/environment';
import { GrpcRequest } from '../models/grpc-request';
import type { Project } from '../models/project';
import { ProtoDirectory } from '../models/proto-directory';
import { ProtoFile } from '../models/proto-file';
import { Request } from '../models/request';
import { RequestGroup } from '../models/request-group';
import { UnitTest } from '../models/unit-test';
import { UnitTestSuite } from '../models/unit-test-suite';
import { WebSocketPayload } from '../models/websocket-payload';
import { WebSocketRequest } from '../models/websocket-request';
import { Workspace } from '../models/workspace';
import type { Insomnia4Data } from '../utils/importers/importers';
import { invariant } from '../utils/invariant';
import { EXPORT_TYPE_API_SPEC, EXPORT_TYPE_COOKIE_JAR, EXPORT_TYPE_ENVIRONMENT, EXPORT_TYPE_GRPC_REQUEST, EXPORT_TYPE_PROTO_DIRECTORY, EXPORT_TYPE_PROTO_FILE, EXPORT_TYPE_REQUEST, EXPORT_TYPE_REQUEST_GROUP, EXPORT_TYPE_UNIT_TEST, EXPORT_TYPE_UNIT_TEST_SUITE, EXPORT_TYPE_WEBSOCKET_PAYLOAD, EXPORT_TYPE_WEBSOCKET_REQUEST, EXPORT_TYPE_WORKSPACE } from './constants';
import { database } from './database';
const exportTypeByModelType = (type: string) => ({
[request.type]: EXPORT_TYPE_REQUEST,
[webSocketPayload.type]: EXPORT_TYPE_WEBSOCKET_PAYLOAD,
[webSocketRequest.type]: EXPORT_TYPE_WEBSOCKET_REQUEST,
[grpcRequest.type]: EXPORT_TYPE_GRPC_REQUEST,
[requestGroup.type]: EXPORT_TYPE_REQUEST_GROUP,
[unitTestSuite.type]: EXPORT_TYPE_UNIT_TEST_SUITE,
[unitTest.type]: EXPORT_TYPE_UNIT_TEST,
[workspace.type]: EXPORT_TYPE_WORKSPACE,
[cookieJar.type]: EXPORT_TYPE_COOKIE_JAR,
[environment.type]: EXPORT_TYPE_ENVIRONMENT,
[apiSpec.type]: EXPORT_TYPE_API_SPEC,
[protoFile.type]: EXPORT_TYPE_PROTO_FILE,
[protoDirectory.type]: EXPORT_TYPE_PROTO_DIRECTORY,
}[type] || undefined);
export async function exportWorkspaceData({
workspaceId,
dirPath,
}: {
workspaceId: string;
dirPath: string;
}) {
const workspaceToExport = await database.get<Workspace>(workspace.type, workspaceId);
invariant(workspaceToExport, `Workspace ${workspaceId} not found`);
const workspaceIds = [workspaceId];
const getRequestGroups = async ({ $in }: { $in: string[] }): Promise<RequestGroup[]> => {
const requestGroups = await database.find<RequestGroup>(requestGroup.type, {
parentId: {
$in,
},
});
const requestGroupIds = requestGroups.map(requestGroup => requestGroup._id);
const childRequestGroups = requestGroupIds.length > 0 ? await getRequestGroups({
$in: requestGroupIds,
}) : [];
return [
...requestGroups,
...childRequestGroups,
];
};
const allRequestGroups = await getRequestGroups({
$in: workspaceIds,
});
const getProtoDirectories = async ({ $in }: { $in: string[] }): Promise<ProtoDirectory[]> => {
const protoDirectories = await database.find<ProtoDirectory>(protoDirectory.type, {
parentId: {
$in,
},
});
const protoDirectoryIds = protoDirectories.map(protoDirectory => protoDirectory._id);
const childProtoDirectories = protoDirectoryIds.length > 0 ? await getProtoDirectories({
$in: protoDirectoryIds,
}) : [];
return [
...protoDirectories,
...childProtoDirectories,
];
};
const allProtoDirectories = await getProtoDirectories({
$in: workspaceIds,
});
const protoFiles = await database.find<ProtoFile>(protoFile.type, {
parentId: {
$in: allProtoDirectories.map(protoDirectory => protoDirectory._id),
},
});
const requests = await database.find<Request>(request.type, {
parentId: {
$in: [
...workspaceIds,
...allRequestGroups.map(requestGroup => requestGroup._id),
],
},
});
const grpcRequests = await database.find<GrpcRequest>(grpcRequest.type, {
parentId: {
$in: [
...workspaceIds,
...allRequestGroups.map(requestGroup => requestGroup._id),
],
},
});
const webSocketRequests = await database.find<WebSocketRequest>(webSocketRequest.type, {
parentId: {
$in: [
...workspaceIds,
...allRequestGroups.map(requestGroup => requestGroup._id),
],
},
});
const baseEnvironments = await database.find<Environment>(environment.type, {
parentId: {
$in: workspaceIds,
},
});
const environments = await database.find<Environment>(environment.type, {
parentId: {
$in: baseEnvironments.map(environment => environment._id),
},
});
const cookieJars = await database.find<CookieJar>(cookieJar.type, {
parentId: {
$in: workspaceIds,
},
});
const apiSpecs = await database.find<ApiSpec>(apiSpec.type, {
parentId: {
$in: workspaceIds,
},
});
const unitTestSuites = await database.find<UnitTestSuite>(unitTestSuite.type, {
parentId: {
$in: workspaceIds,
},
});
const unitTests = await database.find<UnitTest>(unitTest.type, {
parentId: {
$in: unitTestSuites.map(unitTestSuite => unitTestSuite._id),
},
});
const webSocketPayloads = await database.find<WebSocketPayload>(webSocketPayload.type, {
parentId: {
$in: webSocketRequests.map(webSocketRequest => webSocketRequest._id),
},
});
const insomniaExport: Insomnia4Data = {
_type: 'export',
__export_format: 4,
__export_date: new Date(),
__export_source: 'insomnia.desktop.app:v2021.5.0',
resources: [
workspaceToExport,
...requests,
...allRequestGroups,
...environments,
...cookieJars,
...apiSpecs,
...protoFiles,
...allProtoDirectories,
...unitTests,
...unitTestSuites,
...webSocketPayloads,
...webSocketRequests,
...grpcRequests,
].map(({ type, ...model }) => ({
...model,
_type: exportTypeByModelType(type),
})),
};
const filePath = join(dirPath, workspaceId + '.json');
try {
await writeFile(filePath, JSON.stringify(insomniaExport));
} catch (error) {
console.error(error);
}
}
export async function exportAllData({
dirPath,
}: {
dirPath: string;
}): Promise<void> {
const insomniaExportFolder = join(dirPath, `insomnia-export.${Date.now()}`);
await mkdir(insomniaExportFolder);
const projects = await database.all<Project>(project.type);
for (const project of projects) {
const workspaces = await database.find<Workspace>(workspace.type, {
parentId: project._id,
});
for (const workspace of workspaces) {
await exportWorkspaceData({
workspaceId: workspace._id,
dirPath: insomniaExportFolder,
});
}
}
}
-1
View File
@@ -146,7 +146,6 @@ export async function exportRequestsData(
format: 'json' | 'yaml',
) {
const data: Insomnia4Data = {
// @ts-expect-error -- TSCONVERSION maybe this needs to be added to the upstream type?
_type: 'export',
__export_format: EXPORT_FORMAT,
__export_date: new Date(),
+1 -1
View File
@@ -55,7 +55,7 @@ export async function getSendRequestCallbackMemDb(environmentId: string, memDB:
const workspace = await models.workspace.getById(workspaceId);
invariant(workspace, 'failed to find workspace');
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
invariant(settings, 'failed to create settings');
const clientCertificates = await models.clientCertificate.findByParentId(workspaceId);
const caCert = await models.caCertificate.findByParentId(workspaceId);
+3 -3
View File
@@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta
http-equiv="Content-Security-Policy"
content="font-src 'self' data:; connect-src * data:; default-src * insomnia://*; img-src blob: data: * insomnia://*; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src blob: data: mediastream: * insomnia://*;"
content="font-src 'self' data:; connect-src * data: api: insomnia-event-source:; default-src * insomnia://*; img-src blob: data: * insomnia://*; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src blob: data: mediastream: * insomnia://*;"
/>
<link rel="stylesheet" href="./ui/css/styles.css" />
</head>
@@ -37,7 +37,7 @@
cy="36"
r="36"
fill="none"
stroke="var(--hl)"
stroke="var(--hl, rgb(130, 130, 130))"
stroke-opacity="0.1"
stroke-width="4px"
transform="translate(-323 -111) translate(359.016 147.016) scale(4.24956)"
@@ -47,7 +47,7 @@
cy="36"
r="36"
fill="none"
stroke="var(--hl)"
stroke="var(--hl, rgb(130, 130, 130))"
stroke-opacity="0.8"
stroke-width="4px"
stroke-dasharray="56,172,0,0"
@@ -9,6 +9,7 @@ import { userDataFolder } from '../config/config.json';
import { changelogUrl, getAppVersion, isDevelopment, isMac } from './common/constants';
import { database } from './common/database';
import log, { initializeLogging } from './common/log';
import { registerInsomniaStreamProtocol } from './main/api.protocol';
import { backupIfNewerVersionAvailable } from './main/backup';
import { registerElectronHandlers } from './main/ipc/electron';
import { registergRPCHandlers } from './main/ipc/grpc';
@@ -25,6 +26,7 @@ import type { ToastNotification } from './ui/components/toast';
initializeSentry();
registerInsomniaStreamProtocol();
// Handle potential auto-update
if (checkIfRestartNeeded()) {
process.exit(0);
+7 -10
View File
@@ -4,19 +4,18 @@ import { v4 as uuidv4 } from 'uuid';
import * as session from '../account/session';
import { getAccountId } from '../account/session';
import {
getApiBaseURL,
getAppPlatform,
getAppVersion,
getProductName,
getSegmentWriteKey,
} from '../common/constants';
import * as models from '../models/index';
import { axiosRequest } from './network/axios-request';
import { insomniaFetch } from './insomniaFetch';
const analytics = new Analytics({ writeKey: getSegmentWriteKey() });
const getDeviceId = async () => {
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
return settings.deviceId || (await models.settings.update(settings, { deviceId: uuidv4() })).deviceId;
};
@@ -49,7 +48,7 @@ export async function trackSegmentEvent(
event: SegmentEvent,
properties?: Record<string, any>,
) {
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const allowAnalytics = settings.enableAnalytics || session.isLoggedIn();
if (allowAnalytics) {
try {
@@ -77,7 +76,7 @@ export async function trackSegmentEvent(
}
export async function trackPageView(name: string) {
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const allowAnalytics = settings.enableAnalytics || session.isLoggedIn();
if (allowAnalytics) {
try {
@@ -101,12 +100,10 @@ export async function trackPageView(name: string) {
export async function sendTelemetry() {
if (session.isLoggedIn()) {
axiosRequest({
insomniaFetch({
method: 'POST',
url: `${getApiBaseURL()}/v1/telemetry/`,
headers: {
'X-Session-Id': session.getCurrentSessionId(),
},
path: '/v1/telemetry/',
sessionId: session.getCurrentSessionId(),
}).catch((error: unknown) => {
console.warn('[analytics] Unexpected error while sending telemetry', error);
});
@@ -0,0 +1,30 @@
import { app, net, protocol } from 'electron';
import { getApiBaseURL } from '../common/constants';
export interface RegisterProtocolOptions {
scheme: string;
}
const scheme = 'insomnia-event-source';
export async function registerInsomniaStreamProtocol() {
protocol.registerSchemesAsPrivileged([{
scheme,
privileges: { secure: true, standard: true, supportFetchAPI: true },
}]);
await app.whenReady();
if (protocol.isProtocolHandled(scheme)) {
return;
}
protocol.handle(scheme, async function(request) {
const apiURL = getApiBaseURL();
const url = new URL(`${apiURL}/${request.url.replace(`${scheme}://`, '')}`);
const sessionId = new URLSearchParams(url.search).get('sessionId');
request.headers.append('X-Session-Id', sessionId || '');
return net.fetch(url.toString(), request);
});
}
@@ -34,7 +34,7 @@ export function authorizeUserInWindow({
// Fetch user setting to determine whether to validate SSL certificates during auth
const {
validateAuthSSL,
} = await models.settings.getOrCreate();
} = await models.settings.get();
// Create a child window
const child = new BrowserWindow({
+1 -1
View File
@@ -11,7 +11,7 @@ import { insomniaFetch } from './insomniaFetch';
export async function backupIfNewerVersionAvailable() {
try {
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
console.log('[main] Checking for newer version than ', version);
const response = await insomniaFetch<{ url: string }>({
method: 'GET',
+10 -5
View File
@@ -4,7 +4,7 @@ import { getApiBaseURL, getClientString } from '../common/constants';
import { delay } from '../common/misc';
interface FetchConfig {
method: 'POST' | 'PUT' | 'GET';
method: 'POST' | 'PUT' | 'GET' | 'DELETE' | 'PATCH';
path: string;
sessionId: string | null;
data?: unknown;
@@ -26,10 +26,13 @@ const exponentialBackOff = async (url: string, init: RequestInit, retries = 0):
const response = await net.fetch(url, init);
if (response.status === 502 && retries < 5) {
retries++;
await delay(retries * 200);
await delay(retries * 1000);
console.log(`Received 502 from ${url} retrying`);
return exponentialBackOff(url, init, retries);
}
if (!response.ok) {
// TODO: review error status code behaviour with backend, should we parse errors here and return response
// or should we rethrow an error with a response object inside? should we be exposing errors to the app UI?
console.log(`Response not OK: ${response.status} for ${url}`);
}
return response;
@@ -38,7 +41,7 @@ const exponentialBackOff = async (url: string, init: RequestInit, retries = 0):
}
};
export async function insomniaFetch<T = any>({ method, path, data, sessionId, origin }: FetchConfig): Promise<T> {
export async function insomniaFetch<T = void>({ method, path, data, sessionId, origin }: FetchConfig): Promise<T> {
const config: RequestInit = {
method,
headers: {
@@ -51,13 +54,15 @@ export async function insomniaFetch<T = any>({ method, path, data, sessionId, or
if (sessionId === undefined) {
throw new Error(`No session ID provided to ${method}:${path}`);
}
const response = await exponentialBackOff(`${origin || getApiBaseURL()}${path}`, config);
const apiURL = getApiBaseURL();
const response = await exponentialBackOff(`${origin || apiURL}${path}`, config);
const uri = response.headers.get('x-insomnia-command');
if (uri) {
for (const window of BrowserWindow.getAllWindows()) {
window.webContents.send('shell:open', uri);
}
}
const isJson = response.headers.get('content-type') === 'application/json' || path.match(/\.json$/);
const isJson = response.headers.get('content-type')?.includes('application/json') || path.match(/\.json$/);
return isJson ? response.json() : response.text();
}
@@ -15,7 +15,7 @@ interface AxiosRequestMockUserSettings {
}
jest.mock('axios');
jest.spyOn(models.settings, 'getOrCreate');
jest.spyOn(models.settings, 'get');
describe('axiosRequest used for git-sync', () => {
beforeEach(globalBeforeEach);
@@ -46,7 +46,7 @@ describe('axiosRequest used for git-sync', () => {
noProxy: '',
validateSSL: false,
};
(models.settings.getOrCreate as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
(models.settings.get as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
const response = await axiosRequest({ url: 'https://git.acme.com/username/repo-name.git/git-upload-pack' });
expect(response.config.proxy).toBe(false);
});
@@ -59,7 +59,7 @@ describe('axiosRequest used for git-sync', () => {
noProxy: 'localhost,127.0.0.1',
validateSSL: false,
};
(models.settings.getOrCreate as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
(models.settings.get as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
const response = await axiosRequest({ url: 'http://git.acme.com/username/repo-name.git/git-upload-pack' });
expect(response.config.proxy).toEqual({ host: 'some.proxy.com', port: 8080 });
});
@@ -72,7 +72,7 @@ describe('axiosRequest used for git-sync', () => {
noProxy: 'localhost,127.0.0.1',
validateSSL: false,
};
(models.settings.getOrCreate as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
(models.settings.get as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
const response = await axiosRequest({ url: 'http://git.acme.com/username/repo-name.git/git-upload-pack' });
expect(response.config.proxy).toBe(false);
});
@@ -85,7 +85,7 @@ describe('axiosRequest used for git-sync', () => {
noProxy: 'localhost,127.0.0.1',
validateSSL: false,
};
(models.settings.getOrCreate as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
(models.settings.get as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
const response = await axiosRequest({ url: 'https://git.acme.com/username/repo-name.git/git-upload-pack' });
expect(response.config.proxy).toEqual({ host: 'some.proxy.com', port: 8080 });
});
@@ -98,7 +98,7 @@ describe('axiosRequest used for git-sync', () => {
noProxy: 'localhost,127.0.0.1',
validateSSL: false,
};
(models.settings.getOrCreate as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
(models.settings.get as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
const response = await axiosRequest({ url: 'http://git.acme.com/username/repo-name.git/git-upload-pack' });
expect(response.config.proxy).toEqual({ host: 'some.proxy.com', port: 8081 });
});
@@ -111,7 +111,7 @@ describe('axiosRequest used for git-sync', () => {
noProxy: 'localhost,127.0.0.1',
validateSSL: false,
};
(models.settings.getOrCreate as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
(models.settings.get as unknown as jest.Mock).mockImplementation(() => mockInsomniaConfigPanelUserSettings);
const response = await axiosRequest({ url: 'https://git.acme.com/username/repo-name.git/git-upload-pack' });
expect(response.config.proxy).toEqual({ host: 'some.proxy.com', port: 8080 });
});
@@ -7,7 +7,7 @@ import * as models from '../../models';
import { isUrlMatchedInNoProxyRule } from '../../network/is-url-matched-in-no-proxy-rule';
import { setDefaultProtocol } from '../../utils/url/protocol';
export const axiosRequest = async (config: AxiosRequestConfig): Promise<AxiosResponse> => {
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const isHttps = config.url?.indexOf('https:') === 0;
let proxyUrl: string | null = null;
+3 -3
View File
@@ -133,7 +133,7 @@ const openCurlConnection = async (
}
const readyStateChannel = `curl.${request._id}.readyState`;
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const start = performance.now();
const clientCertificates = await models.clientCertificate.findByParentId(options.workspaceId);
const filteredClientCertificates = clientCertificates.filter(c => !c.disabled && urlMatchesCertHost(setDefaultProtocol(c.host, 'https:'), options.url));
@@ -223,7 +223,7 @@ const openCurlConnection = async (
settingStoreCookies: request.settingStoreCookies,
bodyCompression: null,
};
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const res = await models.response.create(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(request._id, { activeResponseId: res._id });
@@ -271,7 +271,7 @@ const openCurlConnection = async (
};
const createErrorResponse = async (responseId: string, requestId: string, environmentId: string | null, timelinePath: string, message: string) => {
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const responsePatch = {
_id: responseId,
parentId: requestId,
@@ -179,7 +179,7 @@ const openWebSocketConnection = async (
const lowerCasedEnabledHeaders = headers
.filter(({ name, disabled }) => Boolean(name) && !disabled)
.reduce(reduceArrayToLowerCaseKeyedDictionary, {});
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const start = performance.now();
const clientCertificates = await models.clientCertificate.findByParentId(options.workspaceId);
@@ -254,7 +254,7 @@ const openWebSocketConnection = async (
settingStoreCookies: request.settingStoreCookies,
};
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const res = await models.webSocketResponse.create(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(request._id, { activeResponseId: res._id });
@@ -298,7 +298,7 @@ const openWebSocketConnection = async (
settingSendCookies: request.settingSendCookies,
settingStoreCookies: request.settingStoreCookies,
};
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const res = await models.webSocketResponse.create(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(request._id, { activeResponseId: res._id });
deleteRequestMaps(request._id, `Unexpected response ${incomingMessage.statusCode}`);
@@ -383,7 +383,7 @@ const openWebSocketConnection = async (
};
const createErrorResponse = async (responseId: string, requestId: string, environmentId: string | null, timelinePath: string, message: string) => {
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const responsePatch = {
_id: responseId,
parentId: requestId,
+1 -1
View File
@@ -13,7 +13,7 @@ let enabled = false;
* Watch setting for changes. This must be called after the DB is initialized.
*/
export function sentryWatchAnalyticsEnabled() {
models.settings.getOrCreate().then(settings => {
models.settings.get().then(settings => {
enabled = settings.enableAnalytics || session.isLoggedIn();
});
+3 -3
View File
@@ -79,14 +79,14 @@ export const init = async () => {
if (isUpdateSupported()) {
// perhaps disable this method of upgrading just incase it trigger before backup is complete
// on app start
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const updateUrl = getUpdateUrl(settings.updateChannel);
if (settings.updateAutomatically && updateUrl) {
_checkForUpdates(updateUrl);
}
// on an interval (3h)
setInterval(async () => {
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const updateUrl = getUpdateUrl(settings.updateChannel);
if (settings.updateAutomatically && updateUrl) {
_checkForUpdates(updateUrl);
@@ -96,7 +96,7 @@ export const init = async () => {
// on check now button pushed
ipcMain.on('manualUpdateCheck', async () => {
console.log('[updater] Manual update check');
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const updateUrl = isUpdateSupported() && getUpdateUrl(settings.updateChannel);
if (!updateUrl) {
_sendUpdateStatus('Updates Not Supported');
+21 -8
View File
@@ -1,7 +1,7 @@
import * as crypto from 'crypto';
import { database as db } from '../common/database';
import type { BaseModel } from './index';
import { type BaseModel } from './index';
export const name = 'Environment';
export const type = 'Environment';
@@ -70,13 +70,26 @@ export async function getOrCreateForParentId(parentId: string) {
});
if (!environments.length) {
return create({
parentId,
name: 'Base Environment',
// Deterministic base env ID. It helps reduce sync complexity since we won't have to
// de-duplicate environments.
_id: `${prefix}_${crypto.createHash('sha1').update(parentId).digest('hex')}`,
});
// Deterministic base env ID. It helps reduce sync complexity since we won't have to
// de-duplicate environments.
const baseEnvironmentId = `${prefix}_${crypto.createHash('sha1').update(parentId).digest('hex')}`;
try {
const baseEnvironment = await create({
parentId,
name: 'Base Environment',
_id: baseEnvironmentId,
});
return baseEnvironment;
} catch (e) {
const existingEnvironment = await getById(baseEnvironmentId);
if (existingEnvironment) {
return existingEnvironment;
}
throw e;
}
}
return environments[environments.length - 1];
@@ -1,12 +1,8 @@
import { describe, expect, it } from '@jest/globals';
import { DEFAULT_PROJECT_ID } from '../../project';
import { sortProjects } from '../project';
const defaultProject = { name: 'a', remoteId: null, _id: DEFAULT_PROJECT_ID };
const localA = { name: 'a', remoteId: null, _id: 'localA' };
const localB = { name: 'b', remoteId: null, _id: 'localB' };
const defaultOrgProject = { name: 'a', remoteId: 'proj_team_123456789345678987654', _id: 'not important' };
const remoteA = { name: 'a', remoteId: 'notNull', _id: 'remoteA' };
const remoteB = { name: 'b', remoteId: 'notNull', _id: 'remoteB' };
@@ -16,18 +12,14 @@ describe('sortProjects', () => {
it('sorts projects by default > local > remote > name', () => {
const unSortedProjects = [
remoteA,
localB,
defaultProject,
defaultOrgProject,
remoteB,
localA,
remote0,
];
const result = sortProjects(unSortedProjects);
const sortedProjects = [
defaultProject,
localA,
localB,
defaultOrgProject,
remote0,
remoteA,
remoteB,
@@ -1,8 +1,7 @@
import { isDefaultProject, isLocalProject, isRemoteProject, Project } from '../project';
import { isDefaultOrganizationProject, Project } from '../project';
export const sortProjects = (projects: Project[]) => [
...projects.filter(isDefaultProject),
...projects.filter(p => isLocalProject(p) && !isDefaultProject(p))
...projects.filter(p => isDefaultOrganizationProject(p))
.sort((a, b) => a.name.localeCompare(b.name)),
...projects.filter(isRemoteProject)
...projects.filter(p => !isDefaultOrganizationProject(p))
.sort((a, b) => a.name.localeCompare(b.name)),
];
+26 -13
View File
@@ -1,17 +1,30 @@
export const type = 'Organization';
export const prefix = 'org';
export interface Organization {
_id: string;
name: string;
interface Branding {
logo_url: string;
}
export const DEFAULT_ORGANIZATION_ID = `${prefix}_default-project`;
export interface Metadata {
organizationType: string;
ownerAccountId: string;
}
export const defaultOrganization: Organization = {
_id: DEFAULT_ORGANIZATION_ID,
name: 'Personal Projects',
};
export interface Organization {
id: string;
name: string;
display_name: string;
branding?: Branding;
metadata: Metadata;
}
export const SCRATCHPAD_ORGANIZATION_ID = 'org_scratchpad';
export const isScratchpadOrganizationId = (organizationId: string) =>
organizationId === SCRATCHPAD_ORGANIZATION_ID;
export const isPersonalOrganization = (organization: Organization) =>
organization.metadata.organizationType === 'personal';
export const isDefaultOrganization = (organization: Organization) => organization._id === DEFAULT_ORGANIZATION_ID;
export const isOwnerOfOrganization = ({
organization,
accountId,
}: {
organization: Organization;
accountId: string;
}) =>
organization.metadata.ownerAccountId === accountId;
+10 -5
View File
@@ -1,6 +1,6 @@
import { database as db } from '../common/database';
import { generateId } from '../common/misc';
import type { BaseModel } from './index';
import { type BaseModel } from './index';
export const name = 'Project';
export const type = 'Project';
@@ -8,13 +8,12 @@ export const prefix = 'proj';
export const canDuplicate = false;
export const canSync = false;
export const DEFAULT_PROJECT_ID = `${prefix}_default-project`;
export const SCRATCHPAD_PROJECT_ID = `${prefix}_scratchpad`;
export const isDefaultProject = (project: Pick<Project, '_id'>) => project._id === DEFAULT_PROJECT_ID;
export const isNotDefaultProject = (project: Pick<Project, '_id'>) => !isDefaultProject(project);
export const isScratchpadProject = (project: Pick<Project, '_id'>) => project._id === SCRATCHPAD_PROJECT_ID;
export const isLocalProject = (project: Pick<Project, 'remoteId'>): project is LocalProject => project.remoteId === null;
export const isRemoteProject = (project: Pick<Project, 'remoteId'>): project is RemoteProject => !isLocalProject(project);
export const projectHasSettings = (project: Pick<Project, '_id'>) => !isDefaultProject(project);
export const projectHasSettings = (project: Pick<Project, '_id'>) => !isScratchpadProject(project);
interface CommonProject {
name: string;
@@ -77,3 +76,9 @@ export async function all() {
const projects = await db.all<Project>(type);
return projects;
}
export function isDefaultOrganizationProject(project: Project) {
// legacy remoteId = proj_team_xxx
// new remoteId = proj_org_xxx
return project.remoteId?.startsWith('proj_team') || project.remoteId?.startsWith('proj_org');
}
+3 -3
View File
@@ -118,7 +118,7 @@ export async function all() {
}
export async function removeForRequest(parentId: string, environmentId?: string | null) {
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const query: Record<string, any> = {
parentId,
};
@@ -149,7 +149,7 @@ async function _findRecentForRequest(
};
// Filter responses by environment if setting is enabled
if ((await models.settings.getOrCreate()).filterResponsesByEnv) {
if ((await models.settings.get()).filterResponsesByEnv) {
query.environmentId = environmentId;
}
@@ -177,7 +177,7 @@ export async function create(patch: Partial<Response> = {}, maxResponses = 20):
const requestVersion = request ? await models.requestVersion.create(request) : null;
patch.requestVersionId = requestVersion ? requestVersion._id : null;
// Filter responses by environment if setting is enabled
const shouldQueryByEnvId = (await models.settings.getOrCreate()).filterResponsesByEnv && patch.hasOwnProperty('environmentId');
const shouldQueryByEnvId = (await models.settings.get()).filterResponsesByEnv && patch.hasOwnProperty('environmentId');
const query = {
parentId,
...(shouldQueryByEnvId ? { environmentId: patch.environmentId } : {}),
+6
View File
@@ -117,6 +117,12 @@ export async function getOrCreate() {
return results[0];
}
export async function get() {
const results = await db.all<Settings>(type) || [];
return results[0];
}
/**
* Ensure map is updated when new hotkeys are added
*/
@@ -91,7 +91,7 @@ export async function all() {
}
export async function removeForRequest(parentId: string, environmentId?: string | null) {
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const query: Record<string, any> = {
parentId,
};
@@ -128,7 +128,7 @@ export async function create(patch: Partial<WebSocketResponse> = {}, maxResponse
};
if (
(await models.settings.getOrCreate()).filterResponsesByEnv &&
(await models.settings.get()).filterResponsesByEnv &&
patch.hasOwnProperty('environmentId')
) {
query.environmentId = patch.environmentId;
@@ -158,7 +158,7 @@ async function _findRecentForRequest(
};
// Filter responses by environment if setting is enabled
if ((await models.settings.getOrCreate()).filterResponsesByEnv) {
if ((await models.settings.get()).filterResponsesByEnv) {
query.environmentId = environmentId;
}
+7 -11
View File
@@ -4,7 +4,7 @@ import { database as db } from '../common/database';
import { strings } from '../common/strings';
import type { BaseModel } from './index';
import * as models from './index';
import { DEFAULT_PROJECT_ID, isProjectId } from './project';
import { isProjectId } from './project';
export const name = 'Workspace';
export const type = 'Workspace';
@@ -51,7 +51,6 @@ export function migrate(doc: Workspace) {
doc = _migrateExtractClientCertificates(doc);
doc = _migrateEnsureName(doc);
doc = _migrateScope(doc);
doc = _migrateIntoDefaultProject(doc);
return doc;
} catch (e) {
console.log('[db] Error during workspace migration', e);
@@ -147,17 +146,14 @@ function _migrateScope(workspace: MigrationWorkspace) {
return workspace as Workspace;
}
function _migrateIntoDefaultProject(workspace: Workspace) {
if (!workspace.parentId) {
console.log(`[db] No workspace parentId found for ${workspace._id} setting default ${DEFAULT_PROJECT_ID}`);
workspace.parentId = DEFAULT_PROJECT_ID;
}
return workspace;
}
function expectParentToBeProject(parentId?: string | null) {
if (parentId && !isProjectId(parentId)) {
throw new Error('Expected the parent of a Workspace to be a Project');
}
}
export const SCRATCHPAD_WORKSPACE_ID = 'wrk_scratchpad';
export function isScratchpad(workspace: Workspace) {
return workspace._id === SCRATCHPAD_WORKSPACE_ID;
}
+1 -1
View File
@@ -56,7 +56,7 @@ export const fetchRequestData = async (requestId: string) => {
const environment = activeEnvironment || await models.environment.getOrCreateForParentId(workspace._id);
invariant(environment, 'failed to find environment ' + activeEnvironmentId);
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
invariant(settings, 'failed to create settings');
const clientCertificates = await models.clientCertificate.findByParentId(workspaceId);
const caCert = await models.caCertificate.findByParentId(workspaceId);
@@ -6,7 +6,7 @@ import { globalBeforeEach } from '../../../__jest__/before-each';
import { getAppVersion } from '../../../common/constants';
import { database as db } from '../../../common/database';
import * as models from '../../../models/index';
import { DEFAULT_PROJECT_ID, Project } from '../../../models/project';
import { Project } from '../../../models/project';
import { WorkspaceScopeKeys } from '../../../models/workspace';
import * as plugin from '../data';
@@ -16,7 +16,8 @@ describe('init()', () => {
beforeEach(globalBeforeEach);
it('initializes correctly', async () => {
const { data } = plugin.init(DEFAULT_PROJECT_ID);
const project = await models.project.create();
const { data } = plugin.init(project._id);
expect(Object.keys(data)).toEqual(['import', 'export']);
expect(Object.keys(data.export).sort()).toEqual(['har', 'insomnia']);
expect(Object.keys(data.import).sort()).toEqual(['raw', 'uri']);
@@ -35,6 +36,7 @@ describe('app.import.*', () => {
modified: 222,
parentId: project._id,
});
await models.settings.getOrCreate();
});
it('uri', async () => {
@@ -135,6 +137,7 @@ describe('app.export.*', () => {
beforeEach(async () => {
await globalBeforeEach();
project = await models.project.create();
await models.settings.getOrCreate();
await models.workspace.create({
_id: 'wrk_1',
created: 111,
+1 -1
View File
@@ -184,7 +184,7 @@ export async function getPlugins(force = false): Promise<Plugin[]> {
}
if (!plugins) {
const settings = await models.settings.getOrCreate();
const settings = await models.settings.get();
const allConfigs: PluginConfigMap = settings.pluginConfig;
const extraPaths = settings.pluginPath
.split(':')
@@ -4,7 +4,7 @@ const sidebarBackground = {
notice: '#f0e137',
warning: '#ff9a1f',
danger: '#ff5631',
surprise: '#a896ff',
surprise: '#4000BF',
info: '#46c1e6',
};
@@ -62,7 +62,7 @@ export default {
notice: '#d8c84d',
warning: '#ec8702',
danger: '#e15251',
surprise: '#8776d5',
surprise: '#4000BF',
info: '#20aed9',
},
},
@@ -7,7 +7,6 @@ import { globalBeforeEach } from '../../../__jest__/before-each';
import { database as db } from '../../../common/database';
import * as models from '../../../models';
import { workspaceModelSchema } from '../../../models/__schemas__/model-schemas';
import { DEFAULT_PROJECT_ID } from '../../../models/project';
import { GIT_CLONE_DIR, GIT_INSOMNIA_DIR, GIT_INSOMNIA_DIR_NAME } from '../git-vcs';
import { NeDBClient } from '../ne-db-client';
import { assertAsyncError, setupDateMocks } from './util';
@@ -21,9 +20,12 @@ describe('NeDBClient', () => {
workspaceBuilder.reset();
setupDateMocks();
// Create some sample models
await models.project.all();
await models.project.create({
_id: 'proj_1',
});
await models.workspace.create({
_id: 'wrk_1',
parentId: 'proj_1',
});
await models.request.create({
_id: 'req_1',
@@ -43,7 +45,7 @@ describe('NeDBClient', () => {
describe('readdir()', () => {
it('reads model IDs from model type folders', async () => {
const neDbClient = new NeDBClient('wrk_1', DEFAULT_PROJECT_ID);
const neDbClient = new NeDBClient('wrk_1', 'proj_1');
const reqDir = path.join(GIT_INSOMNIA_DIR, models.request.type);
const wrkDir = path.join(GIT_INSOMNIA_DIR, models.workspace.type);
expect(await neDbClient.readdir(GIT_CLONE_DIR)).toEqual([GIT_INSOMNIA_DIR_NAME]);
@@ -71,7 +73,7 @@ describe('NeDBClient', () => {
const wrk1Yml = path.join(GIT_INSOMNIA_DIR, models.workspace.type, 'wrk_1.yml');
const req1Yml = path.join(GIT_INSOMNIA_DIR, models.request.type, 'req_1.yml');
const reqXYml = path.join(GIT_INSOMNIA_DIR, models.request.type, 'req_x.yml');
const pNeDB = new NeDBClient('wrk_1', DEFAULT_PROJECT_ID);
const pNeDB = new NeDBClient('wrk_1', 'proj_1');
expect(YAML.parse((await pNeDB.readFile(wrk1Yml, 'utf8')).toString())).toEqual(
expect.objectContaining({
_id: 'wrk_1',
@@ -100,7 +102,7 @@ describe('NeDBClient', () => {
type: 'file',
});
// Act
const neDbClient = new NeDBClient('wrk_1', DEFAULT_PROJECT_ID);
const neDbClient = new NeDBClient('wrk_1', 'proj_1');
// Assert
expect(await neDbClient.stat(GIT_CLONE_DIR)).toEqual(dirType);
expect(await neDbClient.stat(GIT_INSOMNIA_DIR)).toEqual(dirType);
@@ -115,7 +117,7 @@ describe('NeDBClient', () => {
// Arrange
const upsertSpy = jest.spyOn(db, 'upsert');
const workspaceId = 'wrk_1';
const neDbClient = new NeDBClient(workspaceId, DEFAULT_PROJECT_ID);
const neDbClient = new NeDBClient(workspaceId, 'proj_1');
const env = {
_id: 'env_1',
type: models.environment.type,
@@ -133,7 +135,7 @@ describe('NeDBClient', () => {
it('should write files in GIT_INSOMNIA_DIR directory to db', async () => {
// Arrange
const workspaceId = 'wrk_1';
const neDbClient = new NeDBClient(workspaceId, DEFAULT_PROJECT_ID);
const neDbClient = new NeDBClient(workspaceId, 'proj_1');
const upsertSpy = jest.spyOn(db, 'upsert');
const env = {
_id: 'env_1',
@@ -180,7 +182,7 @@ describe('NeDBClient', () => {
it('should throw error if id does not match', async () => {
// Arrange
const workspaceId = 'wrk_1';
const neDbClient = new NeDBClient(workspaceId, DEFAULT_PROJECT_ID);
const neDbClient = new NeDBClient(workspaceId, 'proj_1');
const env = {
_id: 'env_1',
type: models.environment.type,
@@ -198,7 +200,7 @@ describe('NeDBClient', () => {
it('should throw error if type does not match', async () => {
// Arrange
const workspaceId = 'wrk_1';
const neDbClient = new NeDBClient(workspaceId, DEFAULT_PROJECT_ID);
const neDbClient = new NeDBClient(workspaceId, 'proj_1');
const env = {
_id: 'env_1',
type: models.environment.type,
@@ -217,7 +219,7 @@ describe('NeDBClient', () => {
describe('mkdir()', () => {
it('should throw error', async () => {
const workspaceId = 'wrk_1';
const neDbClient = new NeDBClient(workspaceId, DEFAULT_PROJECT_ID);
const neDbClient = new NeDBClient(workspaceId, 'proj_1');
const promiseResult = neDbClient.mkdir();
await expect(promiseResult).rejects.toThrowError('NeDBClient is not writable');
});
@@ -4,7 +4,6 @@ import { getApiBaseURL, getAppWebsiteBaseURL, getGitHubGraphQLApiURL } from '../
export const GITHUB_TOKEN_STORAGE_KEY = 'github-oauth-token';
export const GITHUB_GRAPHQL_API_URL = getGitHubGraphQLApiURL();
const getOauthPageURL = () => getAppWebsiteBaseURL() + '/oauth/github';
/**
* This cache stores the states that are generated for the OAuth flow.
@@ -18,7 +17,7 @@ export function generateAuthorizationUrl() {
const scopes = ['repo', 'read:user', 'user:email'];
const scope = scopes.join(' ');
const url = new URL(getOauthPageURL());
const url = new URL(getAppWebsiteBaseURL() + '/oauth/github');
statesCache.add(state);
@@ -43,8 +42,10 @@ export async function exchangeCodeForToken({
);
}
const apiURL = getApiBaseURL();
return window.main.axiosRequest({
url: getApiBaseURL() + '/v1/oauth/github',
url: apiURL + '/v1/oauth/github',
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -25,9 +25,10 @@ const getGitLabConfig = async () => {
};
}
const apiURL = getApiBaseURL();
// Otherwise fetch the config for the GitLab API
return window.main.axiosRequest({
url: getApiBaseURL() + '/v1/oauth/gitlab/config',
url: apiURL + '/v1/oauth/gitlab/config',
method: 'GET',
}).then(({ data }) => {
return {
@@ -28,7 +28,7 @@ describe('initialize-backend-project', () => {
const workspaceMeta = await models.workspaceMeta.create({ parentId: workspace._id });
vcs.clearBackendProject();
await pushSnapshotOnInitialize({ vcs, project, workspace, workspaceMeta });
await pushSnapshotOnInitialize({ vcs, project, workspace });
expect(pushSpy).not.toHaveBeenCalled();
await expect(models.workspaceMeta.getByParentId(workspace._id)).resolves.toStrictEqual(workspaceMeta);
@@ -40,7 +40,7 @@ describe('initialize-backend-project', () => {
const workspaceMeta = await models.workspaceMeta.create({ parentId: workspace._id });
vcs.switchAndCreateBackendProjectIfNotExist(workspace._id, workspace.name);
await pushSnapshotOnInitialize({ vcs, project, workspace, workspaceMeta });
await pushSnapshotOnInitialize({ vcs, project, workspace });
expect(pushSpy).not.toHaveBeenCalled();
await expect(models.workspaceMeta.getByParentId(workspace._id)).resolves.toStrictEqual(workspaceMeta);
@@ -50,36 +50,22 @@ describe('initialize-backend-project', () => {
const project = await models.project.create({ remoteId: 'abc' });
const anotherProject = await models.project.create({ remoteId: 'def' });
const workspace = await models.workspace.create({ parentId: anotherProject._id });
const workspaceMeta = await models.workspaceMeta.create({ parentId: workspace._id });
vcs.switchAndCreateBackendProjectIfNotExist(workspace._id, workspace.name);
await pushSnapshotOnInitialize({ vcs, project, workspace, workspaceMeta });
await pushSnapshotOnInitialize({ vcs, project, workspace });
expect(pushSpy).not.toHaveBeenCalled();
// await expect(models.workspaceMeta.getByParentId(workspace._id)).resolves.toStrictEqual(workspaceMeta);
});
it('should not push snapshot if not marked for push', async () => {
const project = await models.project.create({ remoteId: 'abc' });
const workspace = await models.workspace.create({ parentId: project._id });
const workspaceMeta = await models.workspaceMeta.create({ parentId: workspace._id, pushSnapshotOnInitialize: false });
vcs.switchAndCreateBackendProjectIfNotExist(workspace._id, workspace.name);
await pushSnapshotOnInitialize({ vcs, project, workspace, workspaceMeta });
expect(pushSpy).not.toHaveBeenCalled();
await expect(models.workspaceMeta.getByParentId(workspace._id)).resolves.toStrictEqual(workspaceMeta);
});
it('should push snapshot if conditions are met', async () => {
const project = await models.project.create({ remoteId: 'abc' });
const project = await models.project.create({ remoteId: 'abc', parentId: 'team_abc' });
const workspace = await models.workspace.create({ parentId: project._id });
const workspaceMeta = await models.workspaceMeta.create({ parentId: workspace._id, pushSnapshotOnInitialize: true });
await models.workspaceMeta.create({ parentId: workspace._id, pushSnapshotOnInitialize: true });
vcs.switchAndCreateBackendProjectIfNotExist(workspace._id, workspace.name);
await pushSnapshotOnInitialize({ vcs, project, workspace, workspaceMeta });
await pushSnapshotOnInitialize({ vcs, project, workspace });
expect(pushSpy).toHaveBeenCalledWith(project.remoteId);
expect(pushSpy).toHaveBeenCalledWith({ teamId: 'team_abc', teamProjectId: project.remoteId });
const updatedMeta = await models.workspaceMeta.getByParentId(workspace._id);
expect(updatedMeta?.pushSnapshotOnInitialize).toBe(false);
});
@@ -1,54 +0,0 @@
import { createBuilder } from '@develohpanda/fluent-builder';
import { beforeEach, describe, expect, it } from '@jest/globals';
import { globalBeforeEach } from '../../../__jest__/before-each';
import * as models from '../../../models';
import { isRemoteProject, Project } from '../../../models/project';
import { isCollection, Workspace, WorkspaceScopeKeys } from '../../../models/workspace';
import { projectSchema, teamSchema } from '../../__schemas__/type-schemas';
import { initializeProjectFromTeam, initializeWorkspaceFromBackendProject } from '../initialize-model-from';
const teamBuilder = createBuilder(teamSchema);
const backendProjectBuilder = createBuilder(projectSchema);
describe('initializeProjectFromTeam', () => {
beforeEach(globalBeforeEach);
it('should initialize project with properties from the team', async () => {
// Arrange
const team = teamBuilder.build();
// Act
const project = await initializeProjectFromTeam(team);
// Assert
expect(isRemoteProject(project)).toBe(true);
expect(project).toMatchObject<Partial<Project>>({
_id:`${models.project.prefix}_${team.id}`,
remoteId: team.id,
name: team.name,
});
});
});
describe('initializeWorkspaceFromProject', () => {
beforeEach(globalBeforeEach);
it('should initialize workspac with properties from the backendProject and project', async () => {
// Arrange
const project = await models.project.create();
const backendProject = backendProjectBuilder.build();
// Act
const workspace = await initializeWorkspaceFromBackendProject(backendProject, project);
// Assert
expect(isCollection(workspace)).toBe(true);
expect(workspace).toMatchObject<Partial<Workspace>>({
_id: backendProject.rootDocumentId,
name: backendProject.name,
parentId: project._id,
scope: WorkspaceScopeKeys.collection,
});
});
});
@@ -4,11 +4,9 @@ import { mocked } from 'jest-mock';
import { globalBeforeEach } from '../../../__jest__/before-each';
import { isLoggedIn as _isLoggedIn } from '../../../account/session';
import { database } from '../../../common/database';
import * as models from '../../../models';
import { backendProjectWithTeamSchema, teamSchema } from '../../__schemas__/type-schemas';
import MemoryDriver from '../../store/drivers/memory-driver';
import { initializeProjectFromTeam } from '../initialize-model-from';
import { migrateCollectionsIntoRemoteProject } from '../migrate-collections';
import { VCS } from '../vcs';
@@ -78,60 +76,4 @@ describe('migrateCollectionsIntoRemoteProject', () => {
expect(vcs.remoteBackendProjectsInAnyTeam).not.toHaveBeenCalled();
await expect(models.workspace.getById(workspaceInLocal._id)).resolves.toStrictEqual(workspaceInLocal);
});
it('does migrate if collection in non-remote project with local backend project - create remote project', async () => {
// Arrange
const vcs = newMockedVcs();
const localProject = await models.project.create();
const workspaceInLocal = await models.workspace.create({ parentId: localProject._id });
const team = teamBuilder.build();
const remoteBackendProjectWithTeam = projectWithTeamBuilder
.rootDocumentId(workspaceInLocal._id)
.team(team)
.build();
vcs.hasBackendProjectForRootDocument.mockResolvedValue(true); // has local backend project
vcs.remoteBackendProjectsInAnyTeam.mockResolvedValue([remoteBackendProjectWithTeam]); // has local backend project
// Act
await migrateCollectionsIntoRemoteProject(vcs);
// Assert
expect(vcs.remoteBackendProjectsInAnyTeam).toHaveBeenCalledTimes(1);
const createdRemoteProject = await models.project.getByRemoteId(team.id);
await expect(models.workspace.getById(workspaceInLocal._id)).resolves.toMatchObject({
...workspaceInLocal,
parentId: createdRemoteProject?._id,
});
});
it('does migrate if collection in non-remote project with local backend project - use existing remote project', async () => {
// Arrange
const vcs = newMockedVcs();
const localProject = await models.project.create();
const workspaceInLocal = await models.workspace.create({ parentId: localProject._id });
const team = teamBuilder.build();
const existingRemoteProject = await initializeProjectFromTeam(team);
await database.batchModifyDocs({ upsert: [existingRemoteProject] });
const remoteProjectWithTeam = projectWithTeamBuilder
.rootDocumentId(workspaceInLocal._id)
.team(team)
.build();
vcs.hasBackendProjectForRootDocument.mockResolvedValue(true); // has local backend project
vcs.remoteBackendProjectsInAnyTeam.mockResolvedValue([remoteProjectWithTeam]); // has local backend project
// Act
await migrateCollectionsIntoRemoteProject(vcs);
// Assert
expect(vcs.remoteBackendProjectsInAnyTeam).toHaveBeenCalledTimes(1);
await expect(models.workspace.getById(workspaceInLocal._id)).resolves.toMatchObject({
...workspaceInLocal,
parentId: existingRemoteProject?._id,
});
});
});
@@ -5,7 +5,6 @@ import { mocked } from 'jest-mock';
import { globalBeforeEach } from '../../../__jest__/before-each';
import { DEFAULT_BRANCH_NAME } from '../../../common/constants';
import * as models from '../../../models';
import { isRemoteProject } from '../../../models/project';
import { Workspace } from '../../../models/workspace';
import { backendProjectWithTeamSchema } from '../../__schemas__/type-schemas';
import MemoryDriver from '../../store/drivers/memory-driver';
@@ -49,7 +48,7 @@ describe('pullBackendProject()', () => {
});
// Act
await pullBackendProject({ vcs, backendProject, remoteProjects: [project].filter(isRemoteProject) });
await pullBackendProject({ vcs, backendProject, remoteProject: project });
// Assert
expect(project?.name).not.toBe(backendProject.team.name); // should not rename if the project already exists
@@ -57,51 +56,60 @@ describe('pullBackendProject()', () => {
const workspaces = await models.workspace.all();
expect(workspaces).toHaveLength(1);
const workspace = workspaces[0];
expect(workspace).toStrictEqual(expect.objectContaining<Partial<Workspace>>({
const expectedWorkspace: Partial<Workspace> = {
_id: backendProject.rootDocumentId,
name: backendProject.name,
parentId: project._id,
scope: 'collection',
}));
};
expect(workspace).toEqual(expect.objectContaining(expectedWorkspace));
});
it('should insert a project and workspace with parent', async () => {
const project = await models.project.create({
name: `${backendProject.team.name} unique`,
remoteId: backendProject.team.id,
});
// Act
await pullBackendProject({ vcs, backendProject, remoteProjects: [] });
await pullBackendProject({ vcs, backendProject, remoteProject: project });
// Assert
const project = await models.project.getByRemoteId(backendProject.team.id);
expect(project?.name).toBe(backendProject.team.name);
const workspaces = await models.workspace.all();
expect(workspaces).toHaveLength(1);
const workspace = workspaces[0];
expect(workspace).toStrictEqual(expect.objectContaining<Partial<Workspace>>({
const expectedWorkspace: Partial<Workspace> = {
_id: backendProject.rootDocumentId,
name: backendProject.name,
parentId: project?._id,
scope: 'collection',
}));
};
expect(workspace).toStrictEqual(expect.objectContaining(expectedWorkspace));
});
it('should update a workspace if the name or parentId is different', async () => {
// Arrange
await models.workspace.create({ _id: backendProject.rootDocumentId, name: 'someName' });
const project = await models.project.create({
name: `${backendProject.team.name} unique`,
remoteId: backendProject.team.id,
});
// Act
await pullBackendProject({ vcs, backendProject, remoteProjects: [] });
await pullBackendProject({ vcs, backendProject, remoteProject: project });
// Assert
const project = await models.project.getByRemoteId(backendProject.team.id);
const workspaces = await models.workspace.all();
expect(workspaces).toHaveLength(1);
const workspace = workspaces[0];
expect(workspace).toStrictEqual(expect.objectContaining<Partial<Workspace>>({
const expectedWorkspace: Partial<Workspace> = {
_id: backendProject.rootDocumentId,
name: backendProject.name,
parentId: project?._id,
}));
};
expect(workspace).toStrictEqual(expect.objectContaining(expectedWorkspace));
});
});
@@ -113,28 +121,31 @@ describe('pullBackendProject()', () => {
const existingReq = await models.request.create({ parentId: existingWrk._id });
vcs.allDocuments.mockResolvedValue([existingWrk, existingReq]);
const project = await models.project.create({
name: `${backendProject.team.name} unique`,
remoteId: backendProject.team.id,
});
// Act
await pullBackendProject({ vcs, backendProject, remoteProjects: [] });
await pullBackendProject({ vcs, backendProject, remoteProject: project });
// Assert
const project = await models.project.getByRemoteId(backendProject.team.id);
const workspaces = await models.workspace.all();
expect(workspaces).toHaveLength(1);
const workspace = workspaces[0];
expect(workspace).toStrictEqual(expect.objectContaining<Partial<Workspace>>({
const expectedWorkspace: Partial<Workspace> = {
_id: backendProject.rootDocumentId,
name: backendProject.name,
parentId: project?._id,
}));
};
expect(workspace).toStrictEqual(expect.objectContaining(expectedWorkspace));
const requests = await models.request.all();
expect(requests).toHaveLength(1);
const request = requests[0];
expect(request).toStrictEqual(existingReq);
expect(vcs.pull).toHaveBeenCalledWith([], project?.remoteId);
expect(vcs.pull).toHaveBeenCalledWith({ candidates: [], teamId: project?.parentId, teamProjectId: project?._id });
});
});
@@ -143,7 +154,7 @@ describe('pullBackendProject()', () => {
vcs.getRemoteBranches.mockRejectedValue(new Error('invalid access to project'));
// Act
const action = () => pullBackendProject({ vcs, backendProject, remoteProjects: [] });
const action = () => pullBackendProject({ vcs, backendProject, remoteProject: { remoteId: '' } });
// Assert
expect(vcs.pull).not.toHaveBeenCalled();
@@ -3,7 +3,6 @@ import * as models from '../../models';
import { BaseModel, canSync } from '../../models';
import { Project } from '../../models/project';
import { Workspace } from '../../models/workspace';
import { WorkspaceMeta } from '../../models/workspace-meta';
import { StatusCandidate } from '../types';
import { VCS } from './vcs';
@@ -34,16 +33,13 @@ export const initializeLocalBackendProjectAndMarkForSync = async ({ vcs, workspa
export const pushSnapshotOnInitialize = async ({
vcs,
workspace,
workspaceMeta,
project: { _id: projectId, remoteId: projectRemoteId },
project: { _id: projectId, remoteId: projectRemoteId, parentId },
}: {
vcs: VCS;
workspace: Workspace;
workspaceMeta?: WorkspaceMeta;
project: Project;
}) => {
const projectIsForWorkspace = projectId === workspace.parentId;
const markedForPush = workspaceMeta?.pushSnapshotOnInitialize;
// A race condition occurs in App.tsx when updating the active workspace
// One code path is that a React Key updates, forcing all children to unmount and remount (https://github.com/Kong/insomnia/blob/9a943879060927d6ab1c21d3e12daba39ad05eea/packages/insomnia-app/app/ui/containers/app.tsx#L1514-L1514)
@@ -51,8 +47,8 @@ export const pushSnapshotOnInitialize = async ({
// This race condition causes us to hit this codepath twice while activating a workspace but the first time it has no project so we shouldn't do anything
const hasProject = vcs.hasBackendProject();
if (markedForPush && projectIsForWorkspace && projectRemoteId && hasProject) {
if (projectIsForWorkspace && projectRemoteId && hasProject) {
await models.workspaceMeta.updateByParentId(workspace._id, { pushSnapshotOnInitialize: false });
await vcs.push(projectRemoteId);
await vcs.push({ teamId: parentId, teamProjectId: projectRemoteId });
}
};
@@ -1,25 +0,0 @@
import * as models from '../../models';
import { RemoteProject } from '../../models/project';
import { Project } from '../../models/project';
import { Workspace, WorkspaceScopeKeys } from '../../models/workspace';
import { Team } from '../types';
import { BackendProject } from '../types';
export const initializeProjectFromTeam = (team: Team) => models.initModel<RemoteProject>(
models.project.type,
{
_id: `${models.project.prefix}_${team.id}`,
remoteId: team.id,
name: team.name,
}
);
export const initializeWorkspaceFromBackendProject = (backendProject: BackendProject, project: Project) => models.initModel<Workspace>(
models.workspace.type,
{
_id: backendProject.rootDocumentId,
name: backendProject.name,
parentId: project._id,
scope: WorkspaceScopeKeys.collection,
}
);
Loaded 100 of 204 files, more files were not shown because too many files have changed in this diff. Show more