Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui): generate some basic test scripts #274

Merged
merged 4 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions packages/ui/src/components/RequestPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@
<div style="margin-bottom: var(--label-margin-bottom); display: flex; justify-content: space-between; align-items: flex-end;">
<div><i class="fa fa-file-export" /> Post Request <i class="fa fa-circle active-script" v-if="script.post_request !== ''"></i></div>
<div style="display: flex; margin-top: 0.5rem">
<button type="button" class="button" @click="generateTests" style="cursor: pointer; margin-right: 0.5rem;">Generate Test Scripts</button>
<SnippetDropdown @optionSelected="insertSnippetPostScript" type="postScripts" />
</div>
</div>
Expand Down Expand Up @@ -461,6 +462,7 @@ import GraphQLSchemaFetcher from '@/components/GraphQLSchemaFetcher.vue'
import GenerateCodeModal from '@/components/modals/GenerateCodeModal.vue'
import EditTagModal from '@/components/modals/EditTagModal.vue'
import { formatSdl } from 'format-graphql'
import { generateTestScripts } from '@/utils/generate-test-scripts'

const renderer = new marked.Renderer()

Expand Down Expand Up @@ -1128,6 +1130,42 @@ export default {

this.urlPreview = url !== '' && url.trim() !== '' ? url : 'No URL'
},
async generateTests() {
const generatedTestScripts = await generateTestScripts()

const pluginData = this.$store.state.plugins.workspace.find(plugin =>
plugin.collectionId === this.activeTab._id && plugin.type === 'script'
)

const { pre_request = '', post_request = '' } = pluginData?.code || {}

try {
const updatedPostRequest = `${post_request}\n${generatedTestScripts}`.trim()

const pluginPayload = {
code: {
pre_request,
post_request: updatedPostRequest
},
workspaceId: null,
collectionId: this.activeTab._id,
type: 'script'
}

if (!pluginData) {
this.$store.commit('addPlugin', pluginPayload)
} else {
this.$store.commit('updatePlugin', {
_id: pluginData._id,
code: pluginPayload.code
})
}

this.$toast.success('Test scripts are generated successfully.')
} catch (e) {
this.$toast.error(`Failed to generate test scripts: ${e.message}`)
}
}
},
mounted() {
emitter.on('response_panel', this.handleResponsePanelEmitter)
Expand Down
14 changes: 7 additions & 7 deletions packages/ui/src/components/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import SettingsModal from './modals/SidebarSettingsModal.vue'
import DuplicateCollectionItemModal from './modals/DuplicateCollectionItemModal.vue'
import GenerateCodeModal from './modals/GenerateCodeModal.vue'
import { mapState } from 'vuex'
import { flattenTree, exportRestfoxCollection, generateNewIdsForTree } from '@/helpers'
import { flattenTree, exportRestfoxCollection, generateNewIdsForTree, deepClone } from '@/helpers'
import { generateCode } from '@/utils/generate-code'
import AddGraphQLRequestModal from '@/components/modals/AddGraphQLRequestModal.vue'

Expand Down Expand Up @@ -258,7 +258,7 @@ export default {
methods: {
async handleClick(clickedSidebarItem) {
if(clickedSidebarItem === 'Delete') {
const collectionItemToDelete = JSON.parse(JSON.stringify(this.activeSidebarItemForContextMenu))
const collectionItemToDelete = deepClone(this.activeSidebarItemForContextMenu)
if(await window.createConfirm('Are you sure?')) {
await this.$store.dispatch('deleteCollectionItem', collectionItemToDelete)
}
Expand All @@ -270,7 +270,7 @@ export default {
}

if(clickedSidebarItem === 'Export') {
let collectionItemToExport = JSON.parse(JSON.stringify(this.activeSidebarItemForContextMenu))
let collectionItemToExport = deepClone(this.activeSidebarItemForContextMenu)
collectionItemToExport.parentId = null

collectionItemToExport = [collectionItemToExport]
Expand All @@ -290,7 +290,7 @@ export default {
}

if(clickedSidebarItem === 'Copy as Curl') {
const request = JSON.parse(JSON.stringify(this.activeSidebarItemForContextMenu))
const request = deepClone(this.activeSidebarItemForContextMenu)
const { environment, parentHeaders, parentAuthentication } = await this.$store.dispatch('getEnvironmentForRequest', { collectionItem: request })
try {
const curlCommand = await generateCode(request, environment, parentHeaders, parentAuthentication, 'shell', 'curl')
Expand All @@ -309,7 +309,7 @@ export default {
}

if(clickedSidebarItem === 'Generate Code') {
this.generateCodeModalCollectionItem = JSON.parse(JSON.stringify(this.activeSidebarItemForContextMenu))
this.generateCodeModalCollectionItem = deepClone(this.activeSidebarItemForContextMenu)
this.generateCodeModalShow = true
}

Expand Down Expand Up @@ -339,7 +339,7 @@ export default {
}

if(clickedSidebarItem === 'Plugins') {
this.pluginManagerCollectionItem = JSON.parse(JSON.stringify(this.activeSidebarItemForContextMenu))
this.pluginManagerCollectionItem = deepClone(this.activeSidebarItemForContextMenu)
this.pluginManagerShow = true
}

Expand All @@ -354,7 +354,7 @@ export default {
}

if(clickedSidebarItem === 'Properties') {
this.settingsModalCollectionItem = JSON.parse(JSON.stringify(this.activeSidebarItemForContextMenu))
this.settingsModalCollectionItem = deepClone(this.activeSidebarItemForContextMenu)
this.settingsModalShow = true
}

Expand Down
5 changes: 5 additions & 0 deletions packages/ui/src/components/SnippetDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ export default defineComponent ({
type: 'option',
label: 'Returns the status code of the response',
value: 'rf.response.getStatusCode()'
},
{
type: 'option',
label: 'Returns the response time in milliseconds',
value: 'rf.response.getResponseTime()'
}
]

Expand Down
5 changes: 5 additions & 0 deletions packages/ui/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,11 @@ export default {
label: 'rf.response.getStatusCode()',
type: 'function',
info: 'Returns the status code of the response',
},
{
info: 'Returns the response time in milliseconds',
type: 'function',
label: 'rf.response.getResponseTime()'
}
],
},
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1836,3 +1836,6 @@ export function jsonStringify(data: any, space: number = getEditorConfig().inden
return JSON.stringify(data, null, space)
}

export function deepClone(obj: any) {
return JSON.parse(JSON.stringify(obj))
}
4 changes: 4 additions & 0 deletions packages/ui/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ export function createResponseContextForPlugin(response: RequestFinalResponse, e
let bufferCopy = response.buffer.slice(0)
const headers = response.headers
const statusCode = response.status
const responseTime = response.timeTaken

const generalContextMethods = {
...generalContextMethodsBase,
Expand Down Expand Up @@ -220,6 +221,9 @@ export function createResponseContextForPlugin(response: RequestFinalResponse, e
getStatusCode() {
return statusCode
},
getResponseTime() {
return responseTime
},
// deprecated but won't be removed
getEnvironmentVariable: generalContextMethods.getEnvVar,
setEnvironmentVariable: generalContextMethods.setEnvVar,
Expand Down
19 changes: 19 additions & 0 deletions packages/ui/src/utils/generate-test-scripts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export async function generateTestScripts() {
return `
test('Status code is 200', () => {
expect(rf.response.getStatusCode()).to.eql(200)
})

test('Response time is less than 500ms', () => {
expect(rf.response.getResponseTime()).to.below(600)
})

test('Body is not empty', () => {
expect(rf.response.getBodyJSON()).to.not.be.empty
})

test('headers are not empty', () => {
expect(rf.response.getHeaders()).to.not.be.empty
})
`
}
Loading