mirror of
https://github.com/Kong/insomnia.git
synced 2026-10-25 08:09:06 -04:00
Import a spec and execute a request (#2887)
* feat: add swagger2 for prism * feat: add test stub * feat: can import from clipboard * feat: click folder, request and send * chore: add comments * fix: now it actually breaks * fix: typo * fix: update webdriver implicit timeout * feat: replace prism with tinyhttp (similar to express)
This commit is contained in:
1 parent
a2cf11b23b
commit
aeafe4a7c9
12 files changed
+345
-1782
No files matched your search
@@ -1,6 +1,9 @@
|
||||
import * as debug from '../modules/debug';
|
||||
import * as client from '../modules/client';
|
||||
import { launchCore, stop } from '../modules/application';
|
||||
import * as dropdown from '../modules/dropdown';
|
||||
import * as settings from '../modules/settings';
|
||||
import fs from 'fs';
|
||||
|
||||
describe('Application launch', function() {
|
||||
jest.setTimeout(50000);
|
||||
@@ -30,6 +33,35 @@ describe('Application launch', function() {
|
||||
await debug.expect200(app);
|
||||
});
|
||||
|
||||
it.each([true, false])(
|
||||
'imports swagger 2 and sends request: new workspace=%s ',
|
||||
async newWorkspace => {
|
||||
await debug.workspaceDropdownExists(app);
|
||||
|
||||
// Copy text to clipboard
|
||||
const buffer = await fs.promises.readFile(`${__dirname}/../fixtures/swagger2.yaml`);
|
||||
const swagger2Text = buffer.toString();
|
||||
await app.electron.clipboard.writeText(swagger2Text);
|
||||
|
||||
// Click dropdown and open import modal
|
||||
const workspaceDropdown = await debug.clickWorkspaceDropdown(app);
|
||||
await dropdown.clickDropdownItemByText(workspaceDropdown, 'Import/Export');
|
||||
|
||||
// Import from clipboard into new/current workspace
|
||||
await settings.importFromClipboard(app, newWorkspace);
|
||||
|
||||
// Click imported folder and request
|
||||
await debug.clickFolderByName(app, 'custom-tag');
|
||||
await debug.clickRequestByName(app, 'get pet by id');
|
||||
|
||||
// Click send
|
||||
await debug.clickSendRequest(app);
|
||||
|
||||
// Ensure 200
|
||||
await debug.expect200(app);
|
||||
},
|
||||
);
|
||||
|
||||
it('sends CSV request and shows rich response', async () => {
|
||||
const url = 'http://127.0.0.1:4010/csv';
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.0"
|
||||
info:
|
||||
version: 1.0.0
|
||||
title: E2E testing specification
|
||||
title: E2E testing specification - openapi 3
|
||||
description: This is a specification used for E2E testing of Insomnia, and is served via prism
|
||||
servers:
|
||||
- url: http://127.0.0.1:4010
|
||||
@@ -0,0 +1,17 @@
|
||||
swagger: "2.0"
|
||||
info:
|
||||
version: 1.0.0
|
||||
title: E2E testing specification - swagger 2
|
||||
description: This is a specification representing the oas3.yaml spec
|
||||
schemes:
|
||||
- http
|
||||
host: 127.0.0.1:4010
|
||||
tags:
|
||||
- name: custom-tag
|
||||
paths:
|
||||
/pets/1:
|
||||
get:
|
||||
summary: get pet by id
|
||||
operationId: findPetById
|
||||
tags:
|
||||
- custom-tag
|
||||
@@ -70,6 +70,12 @@ const launch = async config => {
|
||||
// https://github.com/electron-userland/spectron/issues/60
|
||||
await app.browserWindow.focus();
|
||||
await app.browserWindow.setAlwaysOnTop(true);
|
||||
|
||||
// Set the implicit wait timeout to 0 (webdriver default)
|
||||
// https://webdriver.io/docs/timeouts.html#session-implicit-wait-timeout
|
||||
// Spectron overrides it to an unreasonable value, as per the issue
|
||||
// https://github.com/electron-userland/spectron/issues/763
|
||||
await app.client.setTimeout({ implicit: 0 });
|
||||
});
|
||||
|
||||
return app;
|
||||
|
||||
@@ -4,6 +4,12 @@ export const workspaceDropdownExists = async (app, workspaceName = 'Insomnia') =
|
||||
await app.client.waitUntilTextExists('.workspace-dropdown', workspaceName);
|
||||
};
|
||||
|
||||
export const clickWorkspaceDropdown = async app => {
|
||||
const dropdown = await app.client.react$('WorkspaceDropdown');
|
||||
await dropdown.click();
|
||||
return dropdown;
|
||||
};
|
||||
|
||||
export const createNewRequest = async (app, name) => {
|
||||
await app.client.$('.sidebar .dropdown .fa-plus-circle').then(e => e.click());
|
||||
|
||||
@@ -31,14 +37,29 @@ export const createNewRequest = async (app, name) => {
|
||||
};
|
||||
|
||||
const waitUntilRequestIsActive = async (app, name) => {
|
||||
const requestIsActive = async () => {
|
||||
const requests = await app.client.react$$('SidebarRequestRow', { props: { isActive: true } });
|
||||
const firstRequest = requests[0];
|
||||
const activeRequestName = await firstRequest.react$('Editable').then(e => e.getText());
|
||||
return activeRequestName === name;
|
||||
};
|
||||
const request = await app.client.react$('SidebarRequestRow', {
|
||||
props: { isActive: true, request: { name } },
|
||||
});
|
||||
|
||||
await app.client.waitUntil(requestIsActive);
|
||||
await request.waitForDisplayed();
|
||||
};
|
||||
|
||||
export const clickFolderByName = async (app, name) => {
|
||||
const folder = await app.client.react$('SidebarRequestGroupRow', {
|
||||
props: { requestGroup: { name } },
|
||||
});
|
||||
|
||||
await folder.waitForClickable();
|
||||
await folder.click();
|
||||
};
|
||||
|
||||
export const clickRequestByName = async (app, name) => {
|
||||
const folder = await app.client.react$('SidebarRequestRow', {
|
||||
props: { request: { name } },
|
||||
});
|
||||
|
||||
await folder.waitForClickable();
|
||||
await folder.click();
|
||||
};
|
||||
|
||||
export const typeInUrlBar = async (app, url) => {
|
||||
@@ -53,6 +74,13 @@ export const clickSendRequest = async app => {
|
||||
.react$('RequestUrlBar')
|
||||
.then(e => e.$('.urlbar__send-btn'))
|
||||
.then(e => e.click());
|
||||
|
||||
// Wait for spinner to show
|
||||
const spinner = await app.client.react$('ResponseTimer');
|
||||
await spinner.waitForDisplayed();
|
||||
|
||||
// Wait for spinner to hide
|
||||
await spinner.waitForDisplayed({ reverse: true });
|
||||
};
|
||||
|
||||
export const expect200 = async app => {
|
||||
|
||||
@@ -10,3 +10,11 @@ export const clickDropdownItemByText = async (dropdown, text) => {
|
||||
await item.waitForDisplayed();
|
||||
await item.click();
|
||||
};
|
||||
|
||||
export const clickOpenDropdownItemByText = async (app, text) => {
|
||||
const item = await app.client
|
||||
.$('.dropdown__menu[aria-hidden=false]')
|
||||
.then(e => e.$(`button*=${text}`));
|
||||
await item.waitForDisplayed();
|
||||
await item.click();
|
||||
};
|
||||
@@ -20,3 +20,11 @@ export const close = async (app, modalName) => {
|
||||
|
||||
await modal.$('button.modal__close-btn').then(e => e.click());
|
||||
};
|
||||
|
||||
export const clickModalFooterByText = async (app, modalName, text) => {
|
||||
const modal = await app.client.react$(modalName);
|
||||
await modal.waitForDisplayed();
|
||||
const btn = await modal.$(`.modal__footer`).then(e => e.$(`button*=${text}`));
|
||||
await btn.waitForClickable();
|
||||
await btn.click();
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import { clickTabByText } from './tabs';
|
||||
import { mapAccelerator } from 'spectron-keys';
|
||||
import * as modal from './modal';
|
||||
import * as dropdown from './dropdown';
|
||||
|
||||
export const openWithKeyboardShortcut = async app => {
|
||||
await app.client.keys(mapAccelerator('CommandOrControl+,'));
|
||||
@@ -20,6 +21,17 @@ export const goToPlugins = async app => {
|
||||
await app.client.react$('Plugins').then(e => e.waitForDisplayed());
|
||||
};
|
||||
|
||||
export const importFromClipboard = async (app, newWorkspace = false) => {
|
||||
const importExport = await app.client.react$('ImportExport');
|
||||
await importExport.waitForDisplayed();
|
||||
|
||||
await importExport.$('button*=Import Data').then(e => e.click());
|
||||
|
||||
await dropdown.clickOpenDropdownItemByText(app, 'From Clipboard');
|
||||
|
||||
await modal.clickModalFooterByText(app, 'AskModal', newWorkspace ? 'New Workspace' : 'Current');
|
||||
};
|
||||
|
||||
export const installPlugin = async (app, pluginName) => {
|
||||
const plugins = await app.client.react$('SettingsModal').then(e => e.react$('Plugins'));
|
||||
|
||||
|
||||
+202
-1694
File diff suppressed because it is too large.
Load diff
@@ -2,20 +2,22 @@
|
||||
"private": true,
|
||||
"name": "insomnia-smoke-test",
|
||||
"version": "2.2.26",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"spectron:core:build": "cross-env BUNDLE=build xvfb-maybe jest --detectOpenHandles --testPathPattern core",
|
||||
"spectron:designer:build": "cross-env BUNDLE=build xvfb-maybe jest --detectOpenHandles --testPathPattern designer",
|
||||
"spectron:core:package": "cross-env BUNDLE=package xvfb-maybe jest --detectOpenHandles --testPathPattern core",
|
||||
"spectron:designer:package": "cross-env BUNDLE=package xvfb-maybe jest --detectOpenHandles --testPathPattern designer",
|
||||
"start:prism": "prism mock prism/oas3.yaml",
|
||||
"with-mock": "concurrently --names prism,spectron --success first --kill-others \"npm run start:prism\"",
|
||||
"serve": "node tinyhttp/index.js",
|
||||
"with-mock": "concurrently --names server,spectron --success first --kill-others \"npm run serve\"",
|
||||
"test:core:build": "npm run with-mock \"npm run spectron:core:build\"",
|
||||
"test:designer:build": "npm run with-mock \"npm run spectron:designer:build\"",
|
||||
"test:core:package": "npm run with-mock \"npm run spectron:core:package\"",
|
||||
"test:designer:package": "npm run with-mock \"npm run spectron:designer:package\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@stoplight/prism-cli": "^3.3.6",
|
||||
"@tinyhttp/app": "^1.0.2",
|
||||
"@tinyhttp/logger": "^1.0.2",
|
||||
"concurrently": "^5.3.0",
|
||||
"cross-env": "^7.0.2",
|
||||
"faker": "^5.1.0",
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
openapi: "3.0.0"
|
||||
info:
|
||||
version: 1.0.0
|
||||
title: E2E testing specification
|
||||
description: This is a specification used for E2E testing of Insomnia, and is served via prism
|
||||
servers:
|
||||
- url: http://127.0.0.1:4010
|
||||
paths:
|
||||
/pets/{id}:
|
||||
get:
|
||||
description: Returns a user based on a single ID, if the user does not have access to the pet
|
||||
operationId: find pet by id
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
description: ID of pet to fetch
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
responses:
|
||||
'200':
|
||||
description: pet response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/csv:
|
||||
get:
|
||||
description: Returns CSV content
|
||||
responses:
|
||||
200:
|
||||
description: Get Todo Items
|
||||
content:
|
||||
text/csv:
|
||||
schema: {}
|
||||
example: |
|
||||
a,b,c
|
||||
1,2,3
|
||||
components:
|
||||
schemas:
|
||||
Pet:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/NewPet'
|
||||
- type: object
|
||||
required:
|
||||
- id
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
NewPet:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
Error:
|
||||
type: object
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
message:
|
||||
type: string
|
||||
@@ -0,0 +1,19 @@
|
||||
import { App } from '@tinyhttp/app';
|
||||
import { logger } from '@tinyhttp/logger';
|
||||
|
||||
const app = new App();
|
||||
|
||||
app
|
||||
.use(logger())
|
||||
.get('/pets/:id', (req, res) => {
|
||||
setTimeout(() => {
|
||||
res.status(200).send({ id: req.params.id });
|
||||
}, 500);
|
||||
})
|
||||
.get('/csv', (_, res) => {
|
||||
res
|
||||
.status(200)
|
||||
.header('content-type', 'text/csv')
|
||||
.send(`a,b,c\n1,2,3`);
|
||||
})
|
||||
.listen(4010);
|
||||
Reference in new issue
Block a user