mirror of
https://github.com/Kong/insomnia.git
synced 2026-10-20 22:04:57 -04:00
Merge All Repositories into Monorepo for easier maintenance (#629)
* All projects into monorepo * Update CI * More CI updates * Extracted a bunch of things into packages * Publish - insomnia-plugin-base64@1.0.1 - insomnia-plugin-default-headers@1.0.2 - insomnia-plugin-file@1.0.1 - insomnia-plugin-hash@1.0.1 - insomnia-plugin-now@1.0.1 - insomnia-plugin-request@1.0.1 - insomnia-plugin-response@1.0.1 - insomnia-plugin-uuid@1.0.1 - insomnia-cookies@0.0.2 - insomnia-importers@1.5.2 - insomnia-prettify@0.0.3 - insomnia-url@0.0.2 - insomnia-xpath@0.0.2 * A bunch of small fixes * Improved build script * Fixed * Merge dangling files * Usability refactor * Handle duplicate plugin names
This commit is contained in:
1 parent
c79d7fdd77
commit
549ce23ce8
957 files changed
+44840
-19355
No files matched your search
+3
-3
@@ -20,7 +20,7 @@ install:
|
||||
- npm --version
|
||||
- npm config set msvs_version 2013
|
||||
- npm install 7zip-bin-win > NUL
|
||||
- npm install > NUL
|
||||
- npm run bootstrap
|
||||
- npm test
|
||||
|
||||
cache:
|
||||
@@ -32,14 +32,14 @@ cache:
|
||||
#---------------------------------#
|
||||
|
||||
build_script:
|
||||
- if %APPVEYOR_REPO_TAG%==true npm run build-n-package
|
||||
- if %APPVEYOR_REPO_TAG%==true npm run package-app
|
||||
|
||||
#---------------------------------#
|
||||
# artifacts configuration #
|
||||
#---------------------------------#
|
||||
|
||||
artifacts:
|
||||
- path: dist\squirrel-windows\*
|
||||
- path: packages\insomnia-app\dist\squirrel-windows\*
|
||||
name: dist
|
||||
|
||||
#---------------------------------#
|
||||
|
||||
+14
-19
@@ -1,27 +1,22 @@
|
||||
node_modules
|
||||
.idea
|
||||
.vscode
|
||||
dist/*
|
||||
build/*
|
||||
.DS_Store
|
||||
coverage
|
||||
|
||||
# Generated
|
||||
app/main.min.js
|
||||
app/node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Optional npm cache directory
|
||||
*.pid.lock
|
||||
lib-cov
|
||||
coverage
|
||||
.lock-wscript
|
||||
build/Release
|
||||
node_modules/
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.eslintcache
|
||||
.node_repl_history
|
||||
*.tgz
|
||||
.yarn-integrity
|
||||
.env
|
||||
.idea
|
||||
.DS_Store
|
||||
+8
-10
@@ -35,16 +35,14 @@ cache:
|
||||
- $HOME/.electron
|
||||
- $HOME/.cache
|
||||
|
||||
install:
|
||||
- npm install > /dev/null
|
||||
script:
|
||||
- node --version
|
||||
- npm --version
|
||||
|
||||
script:
|
||||
- npm run bootstrap
|
||||
- npm test
|
||||
|
||||
before_deploy:
|
||||
- npm run build-n-package
|
||||
- npm run package-app
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
@@ -53,10 +51,10 @@ deploy:
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
file:
|
||||
- dist/**/*.zip
|
||||
- dist/**/*.dmg
|
||||
- dist/**/*.deb
|
||||
- dist/**/*.AppImage
|
||||
- dist/**/*.tar.gz
|
||||
- packages/insomnia-app/dist/**/*.zip
|
||||
- packages/insomnia-app/dist/**/*.dmg
|
||||
- packages/insomnia-app/dist/**/*.deb
|
||||
- packages/insomnia-app/dist/**/*.AppImage
|
||||
- packages/insomnia-app/dist/**/*.tar.gz
|
||||
on:
|
||||
tags: true
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
[](https://insomnia.rest)
|
||||
[](https://travis-ci.org/getinsomnia/insomnia)
|
||||
[](https://ci.appveyor.com/project/gschier/insomnia)
|
||||
[](LICENSE)
|
||||
[](https://chat.insomnia.rest/)
|
||||
[](https://twitter.com/getinsomnia)
|
||||
|
||||
@@ -43,16 +41,20 @@ Development on Insomnia can be done on Mac, Windows, or Linux as long as you hav
|
||||
<details>
|
||||
<summary>Initial Dev Setup</summary>
|
||||
|
||||
This repository is structured as a monorepo and contains many Node.JS packages. Each package has
|
||||
it's own set of command, but the most common commands are available from the
|
||||
root `[package.json](package.json)` adn can be accessed using the `npm run ...` command. Here
|
||||
are the only three commands you should need to start developing on the app.
|
||||
|
||||
```bash
|
||||
# Install dependencies and build add-ons for Electron
|
||||
npm install
|
||||
npm run rebuild
|
||||
# Install and Link Dependencies
|
||||
npm run bootstrap
|
||||
|
||||
# Start app
|
||||
npm run dev
|
||||
|
||||
# Run tests
|
||||
# Run Tests
|
||||
npm test
|
||||
|
||||
# Start App with Live Reload
|
||||
npm run start-app
|
||||
```
|
||||
|
||||
</details>
|
||||
@@ -83,7 +85,3 @@ Here is a list of plugins available for installation via NPM.
|
||||
|
||||
[Swaggymnia](https://github.com/mlabouardy/swaggymnia) – Generate [Swagger](https://swagger.io/) documentation for your existing API in Insomnia.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[GNU AGPLv3](LICENSE) © [Insomnia](https://insomnia.rest)
|
||||
@@ -1,146 +0,0 @@
|
||||
import {CookieJar} from 'tough-cookie';
|
||||
import * as cookieUtils from '../cookies';
|
||||
import {globalBeforeEach} from '../../__jest__/before-each';
|
||||
|
||||
describe('jarFromCookies()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('returns valid cookies', done => {
|
||||
const jar = cookieUtils.jarFromCookies([{
|
||||
key: 'foo',
|
||||
value: 'bar',
|
||||
domain: 'google.com'
|
||||
}]);
|
||||
|
||||
jar.store.getAllCookies((err, cookies) => {
|
||||
expect(err).toBeNull();
|
||||
expect(cookies[0].domain).toEqual('google.com');
|
||||
expect(cookies[0].key).toEqual('foo');
|
||||
expect(cookies[0].value).toEqual('bar');
|
||||
expect(cookies[0].creation instanceof Date).toEqual(true);
|
||||
expect(cookies[0].expires).toEqual('Infinity');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('handles malformed JSON', () => {
|
||||
const jar = cookieUtils.jarFromCookies('not a jar');
|
||||
expect(jar.constructor.name).toBe('CookieJar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('cookiesFromJar()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('returns valid jar', async () => {
|
||||
const d = new Date();
|
||||
const initialCookies = [{
|
||||
key: 'bar',
|
||||
value: 'baz',
|
||||
domain: 'insomnia.rest',
|
||||
expires: d
|
||||
}, {
|
||||
// This one will fail to parse, and be skipped
|
||||
bad: 'cookie'
|
||||
}];
|
||||
|
||||
const jar = CookieJar.fromJSON({cookies: initialCookies});
|
||||
|
||||
const cookies = await cookieUtils.cookiesFromJar(jar);
|
||||
|
||||
expect(cookies[0].domain).toBe('insomnia.rest');
|
||||
expect(cookies[0].key).toBe('bar');
|
||||
expect(cookies[0].value).toBe('baz');
|
||||
expect(cookies[0].creation).toMatch(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/);
|
||||
expect(cookies[0].expires).toEqual(d.toISOString());
|
||||
});
|
||||
|
||||
it('handles bad jar', async () => {
|
||||
const jar = CookieJar.fromJSON({cookies: []});
|
||||
|
||||
// MemoryStore never actually throws errors, so lets mock the
|
||||
// function to force it to this time.
|
||||
jar.store.getAllCookies = cb => cb(new Error('Dummy Error'));
|
||||
const cookies = await cookieUtils.cookiesFromJar(jar);
|
||||
|
||||
// Cookies failed to p
|
||||
expect(cookies.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cookieHeaderValueForUri()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('gets cookies for valid case', async () => {
|
||||
const jar = cookieUtils.jarFromCookies([{
|
||||
key: 'foo',
|
||||
value: 'bar',
|
||||
path: '/',
|
||||
domain: 'google.com'
|
||||
}, {
|
||||
key: 'foo',
|
||||
value: 'inner',
|
||||
path: '/inner',
|
||||
domain: 'google.com'
|
||||
}]);
|
||||
|
||||
expect(await cookieUtils.cookieHeaderValueForUri(jar, 'https://google.com/foo/bar'))
|
||||
.toBe('foo=bar');
|
||||
|
||||
expect(await cookieUtils.cookieHeaderValueForUri(jar, 'https://insomnia.rest/'))
|
||||
.toBe('');
|
||||
|
||||
expect(await cookieUtils.cookieHeaderValueForUri(jar, 'https://google.com/inner'))
|
||||
.toBe('foo=inner; foo=bar');
|
||||
});
|
||||
|
||||
it('handles errors properly', async () => {
|
||||
const jar = cookieUtils.jarFromCookies([]);
|
||||
jar.getCookies = (uri, cb) => cb(new Error('Dummy error'));
|
||||
|
||||
expect(
|
||||
await cookieUtils.cookieHeaderValueForUri(jar, 'https://google.com')
|
||||
).toBe('');
|
||||
});
|
||||
|
||||
describe('cookieToString()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('does its thing', async () => {
|
||||
const jar = cookieUtils.jarFromCookies([{
|
||||
key: 'foo',
|
||||
value: 'bar',
|
||||
path: '/',
|
||||
domain: 'google.com'
|
||||
}, {
|
||||
key: 'foo1',
|
||||
value: 'bar',
|
||||
path: '/',
|
||||
domain: 'google.com',
|
||||
hostOnly: true
|
||||
}, {
|
||||
key: 'foo2',
|
||||
value: 'bar',
|
||||
path: '/',
|
||||
domain: 'google.com',
|
||||
hostOnly: false
|
||||
}, {
|
||||
key: 'foo3',
|
||||
value: 'bar',
|
||||
path: '/somepath'
|
||||
}]);
|
||||
|
||||
const cookies = await cookieUtils.cookiesFromJar(jar);
|
||||
|
||||
expect(cookies.length).toBe(4);
|
||||
|
||||
expect(cookieUtils.cookieToString(cookies[0]))
|
||||
.toBe('foo=bar; Domain=google.com; Path=/');
|
||||
|
||||
expect(cookieUtils.cookieToString(cookies[1]))
|
||||
.toBe('foo1=bar; Path=/; Domain=google.com');
|
||||
|
||||
expect(cookieUtils.cookieToString(cookies[2]))
|
||||
.toBe('foo2=bar; Domain=google.com; Path=/');
|
||||
|
||||
expect(cookieUtils.cookieToString(cookies[3]))
|
||||
.toBe('foo3=bar; Path=/somepath');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,234 +0,0 @@
|
||||
import * as misc from '../misc';
|
||||
import {globalBeforeEach} from '../../__jest__/before-each';
|
||||
|
||||
describe('getBasicAuthHeader()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('succeed with username and password', () => {
|
||||
const header = misc.getBasicAuthHeader('user', 'password');
|
||||
expect(header).toEqual({
|
||||
name: 'Authorization',
|
||||
value: 'Basic dXNlcjpwYXNzd29yZA=='
|
||||
});
|
||||
});
|
||||
|
||||
it('succeed with no username', () => {
|
||||
const header = misc.getBasicAuthHeader(null, 'password');
|
||||
expect(header).toEqual({
|
||||
name: 'Authorization',
|
||||
value: 'Basic OnBhc3N3b3Jk'
|
||||
});
|
||||
});
|
||||
|
||||
it('succeed with username and empty password', () => {
|
||||
const header = misc.getBasicAuthHeader('user', '');
|
||||
expect(header).toEqual({
|
||||
name: 'Authorization',
|
||||
value: 'Basic dXNlcjo='
|
||||
});
|
||||
});
|
||||
|
||||
it('succeed with username and null password', () => {
|
||||
const header = misc.getBasicAuthHeader('user', null);
|
||||
expect(header).toEqual({
|
||||
name: 'Authorization',
|
||||
value: 'Basic dXNlcjo='
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasAuthHeader()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('finds valid header', () => {
|
||||
const yes = misc.hasAuthHeader([
|
||||
{name: 'foo', value: 'bar'},
|
||||
{name: 'authorization', value: 'foo'}
|
||||
]);
|
||||
|
||||
expect(yes).toEqual(true);
|
||||
});
|
||||
|
||||
it('finds valid header case insensitive', () => {
|
||||
const yes = misc.hasAuthHeader([
|
||||
{name: 'foo', value: 'bar'},
|
||||
{name: 'AuthOrizAtiOn', value: 'foo'}
|
||||
]);
|
||||
|
||||
expect(yes).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateId()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('generates a valid ID', () => {
|
||||
const id = misc.generateId('foo');
|
||||
expect(id).toMatch(/^foo_[a-z0-9]{32}$/);
|
||||
});
|
||||
|
||||
it('generates without prefix', () => {
|
||||
const id = misc.generateId();
|
||||
expect(id).toMatch(/^[a-z0-9]{32}$/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setDefaultProtocol()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('no-ops on empty url', () => {
|
||||
const url = misc.setDefaultProtocol('');
|
||||
expect(url).toBe('');
|
||||
});
|
||||
|
||||
it('correctly sets protocol for empty', () => {
|
||||
const url = misc.setDefaultProtocol('google.com');
|
||||
expect(url).toBe('http://google.com');
|
||||
});
|
||||
|
||||
it('does not set for valid url', () => {
|
||||
const url = misc.setDefaultProtocol('https://google.com');
|
||||
expect(url).toBe('https://google.com');
|
||||
});
|
||||
|
||||
it('does not set for valid url', () => {
|
||||
const url = misc.setDefaultProtocol('http://google.com');
|
||||
expect(url).toBe('http://google.com');
|
||||
});
|
||||
|
||||
it('does not set for invalid url', () => {
|
||||
const url = misc.setDefaultProtocol('httbad://google.com');
|
||||
expect(url).toBe('httbad://google.com');
|
||||
});
|
||||
});
|
||||
|
||||
describe('prepareUrlForSending()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('does not touch normal url', () => {
|
||||
const url = misc.prepareUrlForSending('http://google.com');
|
||||
expect(url).toBe('http://google.com/');
|
||||
});
|
||||
|
||||
it('works with no protocol', () => {
|
||||
const url = misc.prepareUrlForSending('google.com');
|
||||
expect(url).toBe('http://google.com/');
|
||||
});
|
||||
|
||||
it('encodes pathname', () => {
|
||||
const url = misc.prepareUrlForSending('https://google.com/foo bar/100%/foo');
|
||||
expect(url).toBe('https://google.com/foo%20bar/100%25/foo');
|
||||
});
|
||||
|
||||
it('encodes pathname mixed encoding', () => {
|
||||
const url = misc.prepareUrlForSending('https://google.com/foo bar baz%20qux/100%/foo%25');
|
||||
expect(url).toBe('https://google.com/foo%20bar%20baz%20qux/100%25/foo%25');
|
||||
});
|
||||
|
||||
it('leaves already encoded pathname', () => {
|
||||
const url = misc.prepareUrlForSending('https://google.com/foo%20bar%20baz/100%25/foo');
|
||||
expect(url).toBe('https://google.com/foo%20bar%20baz/100%25/foo');
|
||||
});
|
||||
|
||||
it('encodes querystring', () => {
|
||||
const url = misc.prepareUrlForSending('https://google.com?s=foo bar 100%&hi');
|
||||
expect(url).toBe('https://google.com/?s=foo%20bar%20100%25&hi');
|
||||
});
|
||||
|
||||
it('encodes querystring with mixed spaces', () => {
|
||||
const url = misc.prepareUrlForSending('https://google.com?s=foo %20100%');
|
||||
expect(url).toBe('https://google.com/?s=foo%20%20100%25');
|
||||
});
|
||||
|
||||
it('encodes querystring with repeated keys', () => {
|
||||
const url = misc.prepareUrlForSending('https://google.com/;@,!?s=foo,;@-!&s=foo %20100%');
|
||||
expect(url).toBe('https://google.com/;@,!?s=foo,%3B%40-!&s=foo%20%20100%25');
|
||||
});
|
||||
|
||||
it('doesn\'t decode ignored characters', () => {
|
||||
// Encoded should skip raw versions of @ ; ,
|
||||
const url = misc.prepareUrlForSending('https://google.com/@;,&^+');
|
||||
expect(url).toBe('https://google.com/@;,%26%5E+');
|
||||
|
||||
// Encoded should skip encoded versions of @ ; ,
|
||||
const url2 = misc.prepareUrlForSending('https://google.com/%40%3B%2C%26%5E');
|
||||
expect(url2).toBe('https://google.com/%40%3B%2C%26%5E');
|
||||
});
|
||||
|
||||
it('leaves already encoded characters alone', () => {
|
||||
const url = misc.prepareUrlForSending('https://google.com/%2B%2A%2F>');
|
||||
expect(url).toBe('https://google.com/%2B%2A%2F%3E');
|
||||
});
|
||||
|
||||
it('doesn\'t encode if last param set', () => {
|
||||
const url = misc.prepareUrlForSending('https://google.com/%%?foo=%%', false);
|
||||
expect(url).toBe('https://google.com/%%?foo=%%');
|
||||
});
|
||||
});
|
||||
|
||||
describe('filterHeaders()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('handles bad headers', () => {
|
||||
expect(misc.filterHeaders(null, null)).toEqual([]);
|
||||
expect(misc.filterHeaders([], null)).toEqual([]);
|
||||
expect(misc.filterHeaders(['bad'], null)).toEqual([]);
|
||||
expect(misc.filterHeaders(['bad'], 'good')).toEqual([]);
|
||||
expect(misc.filterHeaders(null, 'good')).toEqual([]);
|
||||
expect(misc.filterHeaders([{name: 'good', value: 'valid'}], null)).toEqual([]);
|
||||
expect(misc.filterHeaders([{name: 'good', value: 'valid'}], 'good'))
|
||||
.toEqual([{name: 'good', value: 'valid'}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('keyedDebounce()', () => {
|
||||
beforeEach(async () => {
|
||||
await globalBeforeEach();
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
it('debounces correctly', () => {
|
||||
const resultsList = [];
|
||||
const fn = misc.keyedDebounce(results => {
|
||||
resultsList.push(results);
|
||||
}, 100);
|
||||
|
||||
fn('foo', 'bar');
|
||||
fn('baz', 'bar');
|
||||
fn('foo', 'bar2');
|
||||
fn('foo', 'bar3');
|
||||
fn('multi', 'foo', 'bar', 'baz');
|
||||
|
||||
expect(setTimeout.mock.calls.length).toBe(5);
|
||||
expect(resultsList).toEqual([]);
|
||||
|
||||
jest.runAllTimers();
|
||||
|
||||
expect(resultsList).toEqual([{
|
||||
foo: ['bar3'],
|
||||
baz: ['bar'],
|
||||
multi: ['foo', 'bar', 'baz']
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('debounce()', () => {
|
||||
beforeEach(async () => {
|
||||
await globalBeforeEach();
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
it('debounces correctly', () => {
|
||||
const resultList = [];
|
||||
const fn = misc.debounce((...args) => {
|
||||
resultList.push(args);
|
||||
}, 100);
|
||||
|
||||
fn('foo');
|
||||
fn('foo');
|
||||
fn('multi', 'foo', 'bar', 'baz');
|
||||
fn('baz', 'bar');
|
||||
fn('foo', 'bar3');
|
||||
|
||||
expect(setTimeout.mock.calls.length).toBe(5);
|
||||
expect(resultList).toEqual([]);
|
||||
|
||||
jest.runAllTimers();
|
||||
|
||||
expect(resultList).toEqual([['foo', 'bar3']]);
|
||||
});
|
||||
});
|
||||
@@ -1,176 +0,0 @@
|
||||
import * as querystringUtils from '../querystring';
|
||||
import {globalBeforeEach} from '../../__jest__/before-each';
|
||||
|
||||
describe('getBasicAuthHeader()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('gets joiner for bare URL', () => {
|
||||
const joiner = querystringUtils.getJoiner('http://google.com');
|
||||
expect(joiner).toBe('?');
|
||||
});
|
||||
|
||||
it('gets joiner for invalid URL', () => {
|
||||
const joiner = querystringUtils.getJoiner('hi');
|
||||
expect(joiner).toBe('?');
|
||||
});
|
||||
|
||||
it('gets joiner for URL with question mark', () => {
|
||||
const joiner = querystringUtils.getJoiner('http://google.com?');
|
||||
expect(joiner).toBe('&');
|
||||
});
|
||||
|
||||
it('gets joiner for URL with params', () => {
|
||||
const joiner = querystringUtils.getJoiner('http://google.com?foo=bar');
|
||||
expect(joiner).toBe('&');
|
||||
});
|
||||
|
||||
it('gets joiner for URL with hash', () => {
|
||||
const joiner = querystringUtils.getJoiner('http://google.com?foo=bar#hi');
|
||||
expect(joiner).toBe('&');
|
||||
});
|
||||
|
||||
it('gets joiner for URL with ampersand', () => {
|
||||
const joiner = querystringUtils.getJoiner(
|
||||
'http://google.com?foo=bar&baz=qux'
|
||||
);
|
||||
expect(joiner).toBe('&');
|
||||
});
|
||||
});
|
||||
|
||||
describe('joinUrl()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('joins bare URL', () => {
|
||||
const url = querystringUtils.joinUrl(
|
||||
'http://google.com',
|
||||
'foo=bar'
|
||||
);
|
||||
expect(url).toBe('http://google.com?foo=bar');
|
||||
});
|
||||
|
||||
it('joins with hash', () => {
|
||||
const url = querystringUtils.joinUrl(
|
||||
'http://google.com#hash',
|
||||
'foo=bar'
|
||||
);
|
||||
expect(url).toBe('http://google.com?foo=bar#hash');
|
||||
});
|
||||
|
||||
it('joins hash and querystring', () => {
|
||||
const url = querystringUtils.joinUrl(
|
||||
'http://google.com?baz=qux#hash',
|
||||
'foo=bar'
|
||||
);
|
||||
expect(url).toBe('http://google.com?baz=qux&foo=bar#hash');
|
||||
});
|
||||
|
||||
it('joins multi-hash and querystring', () => {
|
||||
const url = querystringUtils.joinUrl(
|
||||
'http://google.com?hi=there&baz=qux#hash#hi#hi',
|
||||
'foo=bar'
|
||||
);
|
||||
expect(url).toBe('http://google.com?hi=there&baz=qux&foo=bar#hash#hi#hi');
|
||||
});
|
||||
|
||||
it('joins URL with querystring', () => {
|
||||
const url = querystringUtils.joinUrl(
|
||||
'http://google.com?hi=there',
|
||||
'foo=bar%20baz'
|
||||
);
|
||||
expect(url).toBe('http://google.com?hi=there&foo=bar%20baz');
|
||||
});
|
||||
});
|
||||
|
||||
describe('build()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('builds simple param', () => {
|
||||
const str = querystringUtils.build({name: 'foo', value: 'bar??'});
|
||||
expect(str).toBe('foo=bar%3F%3F');
|
||||
});
|
||||
|
||||
it('builds param without value', () => {
|
||||
const str = querystringUtils.build({name: 'foo'});
|
||||
expect(str).toBe('foo');
|
||||
});
|
||||
|
||||
it('builds empty param without name', () => {
|
||||
const str = querystringUtils.build({value: 'bar'});
|
||||
expect(str).toBe('');
|
||||
});
|
||||
|
||||
it('builds with numbers', () => {
|
||||
const str = querystringUtils.build({name: 'number', value: 10});
|
||||
const str2 = querystringUtils.build({name: 'number', value: 0});
|
||||
|
||||
expect(str).toBe('number=10');
|
||||
expect(str2).toBe('number=0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildFromParams()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('builds from params', () => {
|
||||
const str = querystringUtils.buildFromParams([
|
||||
{name: 'foo', value: 'bar??'},
|
||||
{name: 'hello'},
|
||||
{name: 'hi there', value: 'bar??'},
|
||||
{name: '', value: 'bar??'},
|
||||
{name: '', value: ''}
|
||||
]);
|
||||
|
||||
expect(str).toBe('foo=bar%3F%3F&hello&hi%20there=bar%3F%3F');
|
||||
});
|
||||
it('builds from params', () => {
|
||||
const str = querystringUtils.buildFromParams([
|
||||
{name: 'foo', value: 'bar??'},
|
||||
{name: 'hello'},
|
||||
{name: 'hi there', value: 'bar??'},
|
||||
{name: '', value: 'bar??'},
|
||||
{name: '', value: ''}
|
||||
], false);
|
||||
|
||||
expect(str).toBe('foo=bar%3F%3F&hello=&hi%20there=bar%3F%3F&=bar%3F%3F&=');
|
||||
});
|
||||
});
|
||||
|
||||
describe('deconstructToParams()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('builds from params', () => {
|
||||
const str = querystringUtils.deconstructToParams(
|
||||
'foo=bar%3F%3F&hello&hi%20there=bar%3F%3F&=&=val'
|
||||
);
|
||||
|
||||
expect(str).toEqual([
|
||||
{name: 'foo', value: 'bar??'},
|
||||
{name: 'hello', value: ''},
|
||||
{name: 'hi there', value: 'bar??'}
|
||||
]);
|
||||
});
|
||||
it('builds from params with =', () => {
|
||||
const str = querystringUtils.deconstructToParams(
|
||||
'foo=bar&1=2=3=4&hi'
|
||||
);
|
||||
|
||||
expect(str).toEqual([
|
||||
{name: 'foo', value: 'bar'},
|
||||
{name: '1', value: '2=3=4'},
|
||||
{name: 'hi', value: ''}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deconstructToParams()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('builds from params not strict', () => {
|
||||
const str = querystringUtils.deconstructToParams(
|
||||
'foo=bar%3F%3F&hello&hi%20there=bar%3F%3F&=&=val',
|
||||
false
|
||||
);
|
||||
|
||||
expect(str).toEqual([
|
||||
{name: 'foo', value: 'bar??'},
|
||||
{name: 'hello', value: ''},
|
||||
{name: 'hi there', value: 'bar??'},
|
||||
{name: '', value: ''},
|
||||
{name: '', value: 'val'}
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -1,138 +0,0 @@
|
||||
// @flow
|
||||
import * as util from './misc.js';
|
||||
|
||||
type Parameter = Object & {
|
||||
name: string,
|
||||
value: string
|
||||
}
|
||||
|
||||
/** Join a URL with a querystring */
|
||||
export function joinUrl (url: string, qs: string): string {
|
||||
if (!qs) {
|
||||
return url;
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
return qs;
|
||||
}
|
||||
|
||||
const [base, ...hashes] = url.split('#');
|
||||
|
||||
// TODO: Make this work with URLs that have a #hash component
|
||||
const baseUrl = base || '';
|
||||
const joiner = getJoiner(base);
|
||||
const hash = hashes.length ? `#${hashes.join('#')}` : '';
|
||||
return `${baseUrl}${joiner}${qs}${hash}`;
|
||||
}
|
||||
|
||||
export function extractFromUrl (url: string): string {
|
||||
if (!url) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// NOTE: This only splits on first ? sign. '1=2=3' --> ['1', '2=3']
|
||||
const things = url.split('?');
|
||||
if (things.length === 1) {
|
||||
return '';
|
||||
} else {
|
||||
const qsWithHash = things.slice(1).join('?');
|
||||
return qsWithHash.replace(/#.*/, '');
|
||||
}
|
||||
}
|
||||
|
||||
export function getJoiner (url: string): string {
|
||||
url = url || '';
|
||||
return url.indexOf('?') === -1 ? '?' : '&';
|
||||
}
|
||||
|
||||
/** Build a querystring param out of a name/value pair */
|
||||
export function build (param: Parameter, strict: boolean = true): string {
|
||||
// Skip non-name ones in strict mode
|
||||
if (strict && !param.name) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Cast number values to strings
|
||||
if (typeof param.value === 'number') {
|
||||
param.value += '';
|
||||
}
|
||||
|
||||
if (!strict || param.value) {
|
||||
// Don't encode ',' in values
|
||||
const value = util.flexibleEncodeComponent(param.value || '').replace(/%2C/gi, ',');
|
||||
const name = util.flexibleEncodeComponent(param.name || '');
|
||||
|
||||
return `${name}=${value}`;
|
||||
} else {
|
||||
return util.flexibleEncodeComponent(param.name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a querystring from a list of name/value pairs
|
||||
* @param parameters
|
||||
* @param strict allow empty names and values
|
||||
*/
|
||||
export function buildFromParams (
|
||||
parameters: Array<Parameter>,
|
||||
strict: boolean = true
|
||||
): string {
|
||||
let items = [];
|
||||
|
||||
for (const param of parameters) {
|
||||
let built = build(param, strict);
|
||||
|
||||
if (!built) {
|
||||
continue;
|
||||
}
|
||||
|
||||
items.push(built);
|
||||
}
|
||||
|
||||
return items.join('&');
|
||||
}
|
||||
|
||||
/**
|
||||
* Deconstruct a querystring to name/value pairs
|
||||
* @param qs
|
||||
* @param strict allow empty names and values
|
||||
*/
|
||||
export function deconstructToParams (qs: ?string, strict: boolean = true): Array<Parameter> {
|
||||
const pairs: Array<Parameter> = [];
|
||||
|
||||
if (!qs) {
|
||||
return pairs;
|
||||
}
|
||||
|
||||
const stringPairs = qs.split('&');
|
||||
|
||||
for (let stringPair of stringPairs) {
|
||||
// NOTE: This only splits on first equals sign. '1=2=3' --> ['1', '2=3']
|
||||
const [encodedName, ...encodedValues] = stringPair.split('=');
|
||||
const encodedValue = encodedValues.join('=');
|
||||
|
||||
let name = '';
|
||||
try {
|
||||
name = decodeURIComponent(encodedName || '');
|
||||
} catch (e) {
|
||||
// Just leave it
|
||||
name = encodedName;
|
||||
}
|
||||
|
||||
let value = '';
|
||||
try {
|
||||
value = decodeURIComponent(encodedValue || '');
|
||||
} catch (e) {
|
||||
// Just leave it
|
||||
value = encodedValue;
|
||||
}
|
||||
|
||||
if (strict && !name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pairs.push({name, value});
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
Generated
-2454
File diff suppressed because it is too large.
Load diff
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "insomnia",
|
||||
"version": "5.12.0-beta.3",
|
||||
"productName": "Insomnia",
|
||||
"longName": "Insomnia REST Client",
|
||||
"description": "Debug APIs like a human, not a robot",
|
||||
"homepage": "https://insomnia.rest",
|
||||
"author": "Insomnia <support@insomnia.rest>",
|
||||
"main": "main.min.js",
|
||||
"dependencies": {
|
||||
"aws4": "^1.6.0",
|
||||
"clone": "^2.1.0",
|
||||
"deep-equal": "^1.0.1",
|
||||
"electron-context-menu": "^0.9.0",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"hawk": "^6.0.2",
|
||||
"hkdf": "^0.0.2",
|
||||
"html-entities": "^1.2.0",
|
||||
"iconv-lite": "^0.4.15",
|
||||
"insomnia-httpsnippet": "^1.16.5",
|
||||
"insomnia-importers": "^1.5.0",
|
||||
"insomnia-node-libcurl": "^1.2.3",
|
||||
"jsonpath": "^0.2.12",
|
||||
"marked": "^0.3.6",
|
||||
"mime-types": "^2.1.14",
|
||||
"mkdirp": "^0.5.1",
|
||||
"moment": "^2.18.1",
|
||||
"nedb": "^1.8.0",
|
||||
"node-forge": "^0.7.0",
|
||||
"oauth-1.0a": "^2.2.2",
|
||||
"srp-js": "^0.2.0",
|
||||
"tar": "^3.1.7",
|
||||
"tough-cookie": "^2.3.1",
|
||||
"vkbeautify": "^0.99.1",
|
||||
"whatwg-fetch": "^2.0.1",
|
||||
"xmldom": "^0.1.22"
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import * as templating from '../../index';
|
||||
import {globalBeforeEach} from '../../../__jest__/before-each';
|
||||
|
||||
function assertTemplate (txt, expected) {
|
||||
return async function () {
|
||||
const result = await templating.render(txt);
|
||||
expect(result).toMatch(expected);
|
||||
};
|
||||
}
|
||||
|
||||
function assertTemplateFails (txt, expected) {
|
||||
return async function () {
|
||||
try {
|
||||
await templating.render(txt);
|
||||
fail(`Render should have thrown ${expected}`);
|
||||
} catch (err) {
|
||||
expect(err.message).toBe(expected);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe('Base64EncodeExtension', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('encodes nothing', assertTemplate("{% base64 'encode' %}", ''));
|
||||
it('encodes something', assertTemplate("{% base64 'encode', 'my string' %}", 'bXkgc3RyaW5n'));
|
||||
it('decodes nothing', assertTemplate("{% base64 'decode' %}", ''));
|
||||
it('decodes something', assertTemplate("{% base64 'decode', 'bXkgc3RyaW5n' %}", 'my string'));
|
||||
it('fails on invalid op', assertTemplateFails(
|
||||
"{% base64 'foo' %}",
|
||||
'Unsupported operation "foo". Must be encode or decode.'
|
||||
));
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
import path from 'path';
|
||||
import * as templating from '../../index';
|
||||
import {globalBeforeEach} from '../../../__jest__/before-each';
|
||||
|
||||
function assertTemplate (txt, context, expected) {
|
||||
return async function () {
|
||||
const result = await templating.render(txt, {context});
|
||||
expect(result).toBe(expected);
|
||||
};
|
||||
}
|
||||
|
||||
function assertTemplateFails (txt, context, expected) {
|
||||
return async function () {
|
||||
try {
|
||||
await templating.render(txt, {context});
|
||||
fail(`Render should have thrown ${expected}`);
|
||||
} catch (err) {
|
||||
expect(err.message).toContain(expected);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe('FileExtension', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
const ctx = {path: path.resolve(__dirname, path.join('./test.txt'))};
|
||||
const escapedPath = ctx.path.replace(/\\/g, '\\\\');
|
||||
it('reads from string', assertTemplate(`{% file "${escapedPath}" %}`, ctx, 'Hello World!'));
|
||||
it('reads a file correctly', assertTemplate('{% file path %}', ctx, 'Hello World!'));
|
||||
it('fails on missing file', assertTemplateFails('{% file "/foo" %}', ctx, `ENOENT: no such file or directory, open '${path.resolve('/foo')}'`));
|
||||
it('fails on no 2nd param', assertTemplateFails('{% file %}', ctx, 'No file selected'));
|
||||
it('fails on unknown variable', assertTemplateFails('{% file foo %}', ctx, 'No file selected'));
|
||||
});
|
||||
@@ -1,36 +0,0 @@
|
||||
import * as templating from '../../index';
|
||||
import {globalBeforeEach} from '../../../__jest__/before-each';
|
||||
|
||||
function assertTemplate (txt, expected) {
|
||||
return async function () {
|
||||
const result = await templating.render(txt);
|
||||
expect(result).toMatch(expected);
|
||||
};
|
||||
}
|
||||
|
||||
function assertTemplateFails (txt, expected) {
|
||||
return async function () {
|
||||
try {
|
||||
await templating.render(txt);
|
||||
fail(`Render should have thrown ${expected}`);
|
||||
} catch (err) {
|
||||
expect(err.message).toBe(expected);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const isoRe = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/;
|
||||
const secondsRe = /^\d{10}$/;
|
||||
const millisRe = /^\d{13}$/;
|
||||
|
||||
describe('NowExtension', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('renders default ISO', assertTemplate('{% now %}', isoRe));
|
||||
it('renders ISO-8601', assertTemplate('{% now "ISO-8601" %}', isoRe));
|
||||
it('renders seconds', assertTemplate('{% now "seconds" %}', secondsRe));
|
||||
it('renders s', assertTemplate('{% now "s" %}', secondsRe));
|
||||
it('renders unix', assertTemplate('{% now "unix" %}', secondsRe));
|
||||
it('renders millis', assertTemplate('{% now "millis" %}', millisRe));
|
||||
it('renders ms', assertTemplate('{% now "ms" %}', millisRe));
|
||||
it('fails on other', assertTemplateFails('{% now "foo" %}', 'Invalid date type "foo"'));
|
||||
});
|
||||
@@ -1,85 +0,0 @@
|
||||
import * as templating from '../../index';
|
||||
import * as models from '../../../models';
|
||||
import {cookiesFromJar, jarFromCookies} from '../../../common/cookies';
|
||||
import {getRenderContext} from '../../../common/render';
|
||||
import {globalBeforeEach} from '../../../__jest__/before-each';
|
||||
|
||||
describe('RequestExtension cookie', async () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('should get cookie by name', async () => {
|
||||
// Create necessary models
|
||||
const workspace = await models.workspace.create({name: 'Workspace'});
|
||||
const request = await models.request.create({
|
||||
parentId: workspace._id,
|
||||
url: 'https://insomnia.rest/foo/bar'
|
||||
});
|
||||
const cookieJar = await models.cookieJar.getOrCreateForParentId(workspace._id);
|
||||
const jar = jarFromCookies(cookieJar.cookies);
|
||||
jar.setCookieSync([
|
||||
'foo=bar',
|
||||
'path=/',
|
||||
'domain=.insomnia.rest',
|
||||
'HttpOnly Cache-Control: public, no-cache'
|
||||
].join('; '), request.url);
|
||||
|
||||
const cookies = await cookiesFromJar(jar);
|
||||
await models.cookieJar.update(cookieJar, {cookies});
|
||||
const context = await getRenderContext(request);
|
||||
const result = await templating.render(`{% request 'cookie', 'foo' %}`, {context});
|
||||
|
||||
expect(result).toBe('bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('RequestExtension url', async () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('should get url', async () => {
|
||||
// Create necessary models
|
||||
const workspace = await models.workspace.create({name: 'Workspace'});
|
||||
const request = await models.request.create({
|
||||
parentId: workspace._id,
|
||||
url: 'https://insomnia.rest/foo/bar',
|
||||
parameters: [{name: 'foo', value: 'bar'}]
|
||||
});
|
||||
|
||||
const context = await getRenderContext(request);
|
||||
const result = await templating.render(`{% request 'url' %}`, {context});
|
||||
|
||||
expect(result).toBe('https://insomnia.rest/foo/bar?foo=bar');
|
||||
});
|
||||
|
||||
it('should get rendered url', async () => {
|
||||
// Create necessary models
|
||||
const workspace = await models.workspace.create({name: 'Workspace'});
|
||||
const request = await models.request.create({
|
||||
parentId: workspace._id,
|
||||
url: 'https://insomnia.rest/foo/bar',
|
||||
parameters: [{name: 'foo', value: '{{ foo }}'}]
|
||||
});
|
||||
|
||||
const context = await getRenderContext(request);
|
||||
context.foo = 'Hello World!';
|
||||
const result = await templating.render(`{% request 'url' %}`, {context});
|
||||
|
||||
expect(result).toBe('https://insomnia.rest/foo/bar?foo=Hello%20World!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('RequestExtension header', async () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('should get url', async () => {
|
||||
// Create necessary models
|
||||
const workspace = await models.workspace.create({name: 'Workspace'});
|
||||
const request = await models.request.create({
|
||||
parentId: workspace._id,
|
||||
url: 'https://insomnia.rest/foo/bar',
|
||||
headers: [{name: 'foo', value: '{{ foo }}'}]
|
||||
});
|
||||
|
||||
const context = await getRenderContext(request);
|
||||
context.foo = 'Hello World!';
|
||||
const result = await templating.render(`{% request 'header', 'foo' %}`, {context});
|
||||
|
||||
expect(result).toBe('Hello World!');
|
||||
});
|
||||
});
|
||||
@@ -1,273 +0,0 @@
|
||||
import * as templating from '../../index';
|
||||
import * as models from '../../../models';
|
||||
import {globalBeforeEach} from '../../../__jest__/before-each';
|
||||
|
||||
describe('ResponseExtension General', async () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('fails on no responses', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "body", "${request._id}", "$.foo" %}`);
|
||||
fail('JSON should have failed to parse');
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('No responses for request');
|
||||
}
|
||||
});
|
||||
|
||||
it('fails on no request', async () => {
|
||||
await models.response.create({parentId: 'req_test'}, '{"foo": "bar"}');
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "body", "req_test", "$.foo" %}`);
|
||||
fail('JSON should have failed to parse');
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('Could not find request req_test');
|
||||
}
|
||||
});
|
||||
|
||||
it('fails on empty filter', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({parentId: request._id, statusCode: 200}, '{"foo": "bar"}');
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "body", "${request._id}", "" %}`);
|
||||
fail('Should have failed');
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('No body filter specified');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('ResponseExtension JSONPath', async () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('renders basic response "body", query', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: '{"foo": "bar"}',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
const result = await templating.render(`{% response "body", "${request._id}", "$.foo" %}`);
|
||||
|
||||
expect(result).toBe('bar');
|
||||
});
|
||||
|
||||
it('fails on invalid JSON', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: '{"foo": "bar"',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "body", "${request._id}", "$.foo" %}`);
|
||||
fail('JSON should have failed to parse');
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('Invalid JSON: Unexpected end of JSON input');
|
||||
}
|
||||
});
|
||||
|
||||
it('fails on invalid query', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: '{"foo": "bar"}',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "body", "${request._id}", "$$" %}`);
|
||||
fail('JSON should have failed to parse');
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('Invalid JSONPath query: $$');
|
||||
}
|
||||
});
|
||||
|
||||
it('fails on no results', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: '{"foo": "bar"}',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "body", "${request._id}", "$.missing" %}`);
|
||||
fail('JSON should have failed to parse');
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('Returned no results: $.missing');
|
||||
}
|
||||
});
|
||||
|
||||
it('fails on more than 1 result', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: '{"array": [1,2,3]}',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "body", "${request._id}", "$.array.*" %}`);
|
||||
fail('JSON should have failed to parse');
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('Returned more than one result: $.array.*');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('ResponseExtension XPath', async () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('renders basic response "body" query', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: '<foo><bar>Hello World!</bar></foo>',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
const result = await templating.render(`{% response "body", "${request._id}", "/foo/bar" %}`);
|
||||
|
||||
expect(result).toBe('Hello World!');
|
||||
});
|
||||
|
||||
it('renders basic response "body" attribute query', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: '<foo><bar hello="World!">Hello World!</bar></foo>',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
const result = await templating.render(`{% response "body", "${request._id}", "/foo/bar/@hello" %}`);
|
||||
|
||||
expect(result).toBe('World!');
|
||||
});
|
||||
|
||||
it('no results on invalid XML', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: '<hi></hi></sstr>',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "body", "${request._id}", "/foo" %}`);
|
||||
fail('should have failed');
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('Returned no results: /foo');
|
||||
}
|
||||
});
|
||||
|
||||
it('fails on invalid query', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: '<foo><bar>Hello World!</bar></foo>',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "body", "${request._id}", "//" %}`);
|
||||
fail('should have failed');
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('Invalid XPath query: //');
|
||||
}
|
||||
});
|
||||
|
||||
it('fails on no results', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: '<foo><bar>Hello World!</bar></foo>',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "body", "${request._id}", "/missing" %}`);
|
||||
fail('should have failed');
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('Returned no results: /missing');
|
||||
}
|
||||
});
|
||||
|
||||
it('fails on more than 1 result', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: '<foo><bar>Hello World!</bar><bar>And again!</bar></foo>',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "body", "${request._id}", "/foo/*" %}`);
|
||||
fail('should have failed');
|
||||
} catch (err) {
|
||||
expect(err.message).toContain('Returned more than one result: /foo/*');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('ResponseExtension Header', async () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('renders basic response "header"', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
statusCode: 200,
|
||||
headers: [
|
||||
{name: 'Content-Type', value: 'application/json'},
|
||||
{name: 'Content-Length', value: '20'}
|
||||
]
|
||||
});
|
||||
|
||||
const id = request._id;
|
||||
|
||||
expect(await templating.render(`{% response "header", "${id}", "content-type" %}`))
|
||||
.toBe('application/json');
|
||||
expect(await templating.render(`{% response "header", "${id}", "Content-Type" %}`))
|
||||
.toBe('application/json');
|
||||
expect(await templating.render(`{% response "header", "${id}", "CONTENT-type" %}`))
|
||||
.toBe('application/json');
|
||||
expect(await templating.render(`{% response "header", "${id}", " CONTENT-type " %}`))
|
||||
.toBe('application/json');
|
||||
});
|
||||
|
||||
it('no results on missing header', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
statusCode: 200,
|
||||
headers: [
|
||||
{name: 'Content-Type', value: 'application/json'},
|
||||
{name: 'Content-Length', value: '20'}
|
||||
]
|
||||
});
|
||||
|
||||
try {
|
||||
await templating.render(`{% response "header", "${request._id}", "dne" %}`);
|
||||
fail('should have failed');
|
||||
} catch (err) {
|
||||
expect(err.message).toBe('No header with name "dne".\nChoices are [\n\t"Content-Type",\n\t"Content-Length"\n]');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('ResponseExtension Raw', async () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('renders basic response "header"', async () => {
|
||||
const request = await models.request.create({parentId: 'foo'});
|
||||
await models.response.create({
|
||||
parentId: request._id,
|
||||
body: 'Hello World!',
|
||||
statusCode: 200
|
||||
});
|
||||
|
||||
const result = await templating.render(`{% response "raw", "${request._id}", "" %}`);
|
||||
expect(result).toBe('Hello World!');
|
||||
});
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
import * as templating from '../../index';
|
||||
import {globalBeforeEach} from '../../../__jest__/before-each';
|
||||
|
||||
function assertTemplate (txt, expected) {
|
||||
return async function () {
|
||||
const result = await templating.render(txt);
|
||||
expect(result).toMatch(expected);
|
||||
};
|
||||
}
|
||||
|
||||
const millisRe = /^\d{13}$/;
|
||||
|
||||
describe('TimestampExtension', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('renders basic', assertTemplate('{% timestamp %}', millisRe));
|
||||
});
|
||||
@@ -1,32 +0,0 @@
|
||||
import * as templating from '../../index';
|
||||
import {globalBeforeEach} from '../../../__jest__/before-each';
|
||||
|
||||
function assertTemplate (txt, expected) {
|
||||
return async function () {
|
||||
const result = await templating.render(txt);
|
||||
expect(result).toMatch(expected);
|
||||
};
|
||||
}
|
||||
|
||||
function assertTemplateFails (txt, expected) {
|
||||
return async function () {
|
||||
try {
|
||||
await templating.render(txt);
|
||||
fail(`Render should have thrown ${expected}`);
|
||||
} catch (err) {
|
||||
expect(err.message).toBe(expected);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe('UuidExtension', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('renders default v4', assertTemplate('{% uuid %}', 'dd2ccc1a-2745-477a-881a-9e8ef9d42403'));
|
||||
it('renders 4', assertTemplate('{% uuid "4" %}', 'e3e96e5f-dd68-4229-8b66-dee1f0940f3d'));
|
||||
it('renders 4 num', assertTemplate('{% uuid 4 %}', 'a262d22b-5fa8-491c-9bd9-58fba03e301e'));
|
||||
it('renders v4', assertTemplate('{% uuid "v4" %}', '2e7c2688-09ee-44b8-900d-5cbbaa7d3a19'));
|
||||
it('renders 1', assertTemplate('{% uuid "1" %}', 'f7272c80-f493-11e6-bc64-92361f002671'));
|
||||
it('renders 1 num', assertTemplate('{% uuid 1 %}', 'f7272f0a-f493-11e6-bc64-92361f002671'));
|
||||
it('renders v1', assertTemplate('{% uuid "v1" %}', 'f72733a6-f493-11e6-bc64-92361f002671'));
|
||||
it('fails on other', assertTemplateFails('{% uuid "foo" %}', 'Invalid UUID type "foo"'));
|
||||
});
|
||||
@@ -1,9 +0,0 @@
|
||||
export default {
|
||||
deprecated: true,
|
||||
name: 'timestamp',
|
||||
displayName: 'Timestamp',
|
||||
description: 'generate timestamp in milliseconds',
|
||||
run (context) {
|
||||
return Date.now();
|
||||
}
|
||||
};
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"lerna": "2.5.1",
|
||||
"version": "independent",
|
||||
"packages": [
|
||||
"plugins/*",
|
||||
"packages/*",
|
||||
"website"
|
||||
],
|
||||
"commands": {
|
||||
"publish": {
|
||||
"ignore": [
|
||||
"insomnia-app",
|
||||
"insomnia-website"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[build]
|
||||
publish = "website/_speedpack"
|
||||
command = "npm run build-website"
|
||||
|
||||
[context.production.environment]
|
||||
HUGO_VERSION = "0.30"
|
||||
|
||||
[context.deploy-preview.environment]
|
||||
HUGO_VERSION = "0.30"
|
||||
Generated
+1879
-15097
File diff suppressed because it is too large.
Load diff
+14
-150
@@ -1,161 +1,25 @@
|
||||
{
|
||||
"name": "insomnia-dev",
|
||||
"name": "insomnia",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "Insomnia App",
|
||||
"cache": 3,
|
||||
"main": "main.js",
|
||||
"licence": "GNU AGPLv3",
|
||||
"homepage": "https://insomnia.rest",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"author": "Gregory Schier <gschier1990@gmail.com>",
|
||||
"repository": "https://github.com/getinsomnia/insomnia",
|
||||
"bugs": {
|
||||
"url": "https://github.com/getinsomnia/insomnia"
|
||||
},
|
||||
"scripts": {
|
||||
"test:lint": "eslint \"**/*.js\" \"**/*.html\" \"**/*.json\"",
|
||||
"test:noisy": "cross-env NODE_ENV=test jest",
|
||||
"test:coverage": "cross-env NODE_ENV=test jest --coverage --silent && open ./coverage/lcov-report/index.html",
|
||||
"test:watch": "cross-env NODE_ENV=test jest --silent --watch",
|
||||
"test:flow": "flow check",
|
||||
"test": "npm run test:flow && npm run test:lint && cross-env NODE_ENV=test jest --silent --maxWorkers 1",
|
||||
"start-hot": "npm run build-main && cross-env HOT=1 INSOMNIA_ENV=development electron app",
|
||||
"build-main": "cross-env NODE_ENV=development webpack --config ./webpack/webpack.config.electron.babel.js",
|
||||
"hot-server": "webpack-dev-server --config ./webpack/webpack.config.development.babel.js",
|
||||
"dev": "concurrently --kill-others \"npm run hot-server\" \"npm run start-hot\"",
|
||||
"rebuild": "electron-rebuild -f -w node-libcurl",
|
||||
"package": "node ./scripts/package.js",
|
||||
"build": "node ./scripts/build.js",
|
||||
"build-n-package": "npm run build && npm run package"
|
||||
},
|
||||
"dev": {
|
||||
"webpack-dev-server-port": 3333
|
||||
},
|
||||
"jest": {
|
||||
"setupFiles": [
|
||||
"./__jest__/setup.js"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"\\.(css|less|png)$": "<rootDir>/__mocks__/dummy.js",
|
||||
"^worker-loader!": "<rootDir>/__mocks__/dummy.js"
|
||||
},
|
||||
"testMatch": [
|
||||
"**/__tests__/**/*.test.js?(x)"
|
||||
],
|
||||
"rootDir": "app",
|
||||
"verbose": false,
|
||||
"resetMocks": true,
|
||||
"resetModules": true,
|
||||
"collectCoverage": false,
|
||||
"collectCoverageFrom": [
|
||||
"**/*.js",
|
||||
"!**/*.min.js",
|
||||
"!**/main.development.js",
|
||||
"!**/static/**",
|
||||
"!**/ui/components/**",
|
||||
"!**/__fixtures__/**",
|
||||
"!**/__tests__/**",
|
||||
"!**/__jest__/**",
|
||||
"!**/__mocks__/**",
|
||||
"!**/node_modules/**"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"autobind-decorator": "^1.3.4",
|
||||
"aws4": "^1.6.0",
|
||||
"classnames": "^2.2.5",
|
||||
"clone": "^2.1.0",
|
||||
"codemirror": "^5.24.2",
|
||||
"codemirror-graphql": "^0.6.11",
|
||||
"deep-equal": "^1.0.1",
|
||||
"electron-context-menu": "^0.9.0",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"graphql": "^0.10.5",
|
||||
"hawk": "^6.0.2",
|
||||
"highlight.js": "^9.12.0",
|
||||
"hkdf": "^0.0.2",
|
||||
"html-entities": "^1.2.0",
|
||||
"iconv-lite": "^0.4.15",
|
||||
"insomnia-httpsnippet": "^1.16.5",
|
||||
"insomnia-importers": "^1.5.0",
|
||||
"insomnia-node-libcurl": "^1.2.3",
|
||||
"jsonlint": "^1.6.2",
|
||||
"jsonpath": "^0.2.12",
|
||||
"jwt-authentication": "^0.3.3",
|
||||
"marked": "^0.3.6",
|
||||
"mime-types": "^2.1.14",
|
||||
"mkdirp": "^0.5.1",
|
||||
"moment": "^2.18.1",
|
||||
"multiparty": "^4.1.3",
|
||||
"nedb": "^1.8.0",
|
||||
"node-forge": "^0.7.0",
|
||||
"nunjucks": "^3.0.0",
|
||||
"oauth-1.0a": "^2.2.2",
|
||||
"pdfjs-dist": "^1.9.640",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^16.0.0",
|
||||
"react-dnd": "^2.4.0",
|
||||
"react-dnd-html5-backend": "^2.4.1",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-tabs": "^2.1.1",
|
||||
"redux": "^3.7.2",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"reselect": "^3.0.1",
|
||||
"srp-js": "^0.2.0",
|
||||
"tar": "^3.1.7",
|
||||
"tough-cookie": "^2.3.1",
|
||||
"uuid": "^3.0.0",
|
||||
"vkbeautify": "^0.99.1",
|
||||
"whatwg-fetch": "^2.0.1",
|
||||
"xmldom": "^0.1.22",
|
||||
"xpath": "^0.0.23"
|
||||
"bootstrap": "lerna bootstrap && lerna run rebuild",
|
||||
"clean": "lerna run clean --stream",
|
||||
"test": "lerna run test --stream",
|
||||
"start-app": "lerna run start --stream --scope=insomnia-app",
|
||||
"start-website": "lerna run start --stream --scope=insomnia-website",
|
||||
"build-app": "lerna run build --stream --scope=insomnia-app",
|
||||
"build-website": "lerna run build --stream --scope=insomnia-website",
|
||||
"package-app": "lerna run package --stream --scope=insomnia-app"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.23.0",
|
||||
"babel-core": "^6.23.1",
|
||||
"babel-eslint": "^7.1.1",
|
||||
"babel-jest": "^19.0.0",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.23.0",
|
||||
"babel-preset-env": "^1.6.0",
|
||||
"babel-preset-flow": "^6.23.0",
|
||||
"babel-preset-react": "^6.23.0",
|
||||
"concurrently": "^3.5.0",
|
||||
"cross-env": "^2.0.0",
|
||||
"css-loader": "^0.28.7",
|
||||
"electron": "^1.7.9",
|
||||
"electron-builder": "^19.45.5",
|
||||
"electron-builder-lib": "^19.46.3",
|
||||
"electron-builder-squirrel-windows": "^19.46.0",
|
||||
"electron-rebuild": "^1.6.0",
|
||||
"eslint": "^3.16.1",
|
||||
"eslint-config-semistandard": "^11.0.0",
|
||||
"eslint-config-standard": "^10.2.1",
|
||||
"eslint-plugin-filenames": "^1.1.0",
|
||||
"eslint-plugin-flowtype": "^2.36.0",
|
||||
"eslint-plugin-html": "^2.0.1",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"eslint-plugin-jest": "^19.0.1",
|
||||
"eslint-plugin-json": "^1.2.0",
|
||||
"eslint-plugin-node": "^5.2.1",
|
||||
"eslint-plugin-promise": "^3.5.0",
|
||||
"eslint-plugin-react": "^7.4.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"file-loader": "^1.1.5",
|
||||
"flow-bin": "^0.58.0",
|
||||
"flow-bin": "^0.59.0",
|
||||
"jest": "^21.2.1",
|
||||
"less": "^2.7.2",
|
||||
"less-loader": "^4.0.5",
|
||||
"ncp": "^2.0.0",
|
||||
"npm": "^5.5.1",
|
||||
"react-hot-loader": "^3.1.3",
|
||||
"redux-mock-store": "^1.0.2",
|
||||
"rimraf": "^2.6.2",
|
||||
"style-loader": "^0.19.0",
|
||||
"url-loader": "^0.6.2",
|
||||
"webpack": "^3.5.5",
|
||||
"webpack-dev-server": "^2.9.4",
|
||||
"webpack-target-electron-renderer": "^0.4.0"
|
||||
"lerna": "^2.5.1"
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"appId": "com.insomnia.app",
|
||||
"publish": false,
|
||||
"extraResources": [
|
||||
{
|
||||
"from": "./bin",
|
||||
"to": "./bin",
|
||||
"filter": "yarn-standalone.js"
|
||||
}
|
||||
],
|
||||
"protocols": [
|
||||
{
|
||||
"name": "Insomnia",
|
||||
"role": "Viewer",
|
||||
"schemes": [
|
||||
"insomnia"
|
||||
]
|
||||
}
|
||||
],
|
||||
"fileAssociations": [],
|
||||
"directories": {
|
||||
"app": "build",
|
||||
"output": "dist"
|
||||
},
|
||||
"mac": {
|
||||
"category": "public.app-category.developer-tools",
|
||||
"target": [
|
||||
"dmg",
|
||||
"zip"
|
||||
]
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
"squirrel",
|
||||
"zip"
|
||||
]
|
||||
},
|
||||
"linux": {
|
||||
"executableName": "insomnia",
|
||||
"synopsis": "A simple, beautiful, and free REST API client",
|
||||
"category": "Development",
|
||||
"target": [
|
||||
"AppImage",
|
||||
"deb",
|
||||
"tar.gz"
|
||||
]
|
||||
},
|
||||
"deb": {
|
||||
"depends": [
|
||||
"gconf2",
|
||||
"gconf-service",
|
||||
"libnotify4",
|
||||
"libappindicator1",
|
||||
"libxtst6",
|
||||
"libnss3",
|
||||
"libcurl3"
|
||||
]
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,6 @@
|
||||
dist
|
||||
build
|
||||
|
||||
# Generated
|
||||
app/main.min.js
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
8
|
||||
File renamed without changes.
@@ -0,0 +1,3 @@
|
||||
# Insomnia App
|
||||
|
||||
The main desktop application.
|
||||
File renamed without changes.
@@ -17,6 +17,7 @@ const localStorageMock = (function () {
|
||||
})();
|
||||
|
||||
// Don't console log during testing. It's annoying
|
||||
global.__DEV__ = false;
|
||||
global.console.log = () => null;
|
||||
global.localStorage = localStorageMock;
|
||||
global.requestAnimationFrame = cb => process.nextTick(cb);
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,14 +1,12 @@
|
||||
import * as appPackage from '../package.json';
|
||||
import * as globalPackage from '../../package.json';
|
||||
import {globalBeforeEach} from '../__jest__/before-each';
|
||||
|
||||
describe('package.json', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('all app dependencies should be same in global', () => {
|
||||
for (const name of Object.keys(appPackage.dependencies)) {
|
||||
const expected = globalPackage.dependencies[name];
|
||||
const actual = appPackage.dependencies[name];
|
||||
expect(`${name}::${actual}`).toBe(`${name}::${expected}`);
|
||||
it('all packed dependencies should exist', () => {
|
||||
for (const name of globalPackage.packedDependencies) {
|
||||
const version = globalPackage.dependencies[name];
|
||||
expect(version).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,108 @@
|
||||
import * as misc from '../misc';
|
||||
import {globalBeforeEach} from '../../__jest__/before-each';
|
||||
|
||||
describe('hasAuthHeader()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('finds valid header', () => {
|
||||
const yes = misc.hasAuthHeader([
|
||||
{name: 'foo', value: 'bar'},
|
||||
{name: 'authorization', value: 'foo'}
|
||||
]);
|
||||
|
||||
expect(yes).toEqual(true);
|
||||
});
|
||||
|
||||
it('finds valid header case insensitive', () => {
|
||||
const yes = misc.hasAuthHeader([
|
||||
{name: 'foo', value: 'bar'},
|
||||
{name: 'AuthOrizAtiOn', value: 'foo'}
|
||||
]);
|
||||
|
||||
expect(yes).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateId()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('generates a valid ID', () => {
|
||||
const id = misc.generateId('foo');
|
||||
expect(id).toMatch(/^foo_[a-z0-9]{32}$/);
|
||||
});
|
||||
|
||||
it('generates without prefix', () => {
|
||||
const id = misc.generateId();
|
||||
expect(id).toMatch(/^[a-z0-9]{32}$/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('filterHeaders()', () => {
|
||||
beforeEach(globalBeforeEach);
|
||||
it('handles bad headers', () => {
|
||||
expect(misc.filterHeaders(null, null)).toEqual([]);
|
||||
expect(misc.filterHeaders([], null)).toEqual([]);
|
||||
expect(misc.filterHeaders(['bad'], null)).toEqual([]);
|
||||
expect(misc.filterHeaders(['bad'], 'good')).toEqual([]);
|
||||
expect(misc.filterHeaders(null, 'good')).toEqual([]);
|
||||
expect(misc.filterHeaders([{name: 'good', value: 'valid'}], null)).toEqual([]);
|
||||
expect(misc.filterHeaders([{name: 'good', value: 'valid'}], 'good'))
|
||||
.toEqual([{name: 'good', value: 'valid'}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('keyedDebounce()', () => {
|
||||
beforeEach(async () => {
|
||||
await globalBeforeEach();
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
it('debounces correctly', () => {
|
||||
const resultsList = [];
|
||||
const fn = misc.keyedDebounce(results => {
|
||||
resultsList.push(results);
|
||||
}, 100);
|
||||
|
||||
fn('foo', 'bar');
|
||||
fn('baz', 'bar');
|
||||
fn('foo', 'bar2');
|
||||
fn('foo', 'bar3');
|
||||
fn('multi', 'foo', 'bar', 'baz');
|
||||
|
||||
expect(setTimeout.mock.calls.length).toBe(5);
|
||||
expect(resultsList).toEqual([]);
|
||||
|
||||
jest.runAllTimers();
|
||||
|
||||
expect(resultsList).toEqual([{
|
||||
foo: ['bar3'],
|
||||
baz: ['bar'],
|
||||
multi: ['foo', 'bar', 'baz']
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('debounce()', () => {
|
||||
beforeEach(async () => {
|
||||
await globalBeforeEach();
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
it('debounces correctly', () => {
|
||||
const resultList = [];
|
||||
const fn = misc.debounce((...args) => {
|
||||
resultList.push(args);
|
||||
}, 100);
|
||||
|
||||
fn('foo');
|
||||
fn('foo');
|
||||
fn('multi', 'foo', 'bar', 'baz');
|
||||
fn('baz', 'bar');
|
||||
fn('foo', 'bar3');
|
||||
|
||||
expect(setTimeout.mock.calls.length).toBe(5);
|
||||
expect(resultList).toEqual([]);
|
||||
|
||||
jest.runAllTimers();
|
||||
|
||||
expect(resultList).toEqual([['foo', 'bar3']]);
|
||||
});
|
||||
});
|
||||
File renamed without changes.
@@ -1,11 +1,11 @@
|
||||
// @flow
|
||||
import * as models from '../models/index';
|
||||
import {buildQueryStringFromParams, joinUrlAndQueryString} from 'insomnia-url';
|
||||
import * as electron from 'electron';
|
||||
import uuid from 'uuid';
|
||||
import {GA_ID, GA_LOCATION, getAppPlatform, getAppVersion, isDevelopment} from './constants';
|
||||
import {getAccountId} from '../sync/session';
|
||||
import type {RequestParameter} from '../models/request';
|
||||
import * as querystring from './querystring';
|
||||
import {getScreenResolution, getUserLanguage, getViewportSize} from './misc';
|
||||
|
||||
const DIMENSION_PLATFORM = 1;
|
||||
@@ -137,11 +137,11 @@ async function _sendToGoogle (params: Array<RequestParameter>) {
|
||||
|
||||
const baseParams = await _getDefaultParams();
|
||||
const allParams = [...baseParams, ...params];
|
||||
const qs = querystring.buildFromParams(allParams);
|
||||
const qs = buildQueryStringFromParams(allParams);
|
||||
const baseUrl = isDevelopment()
|
||||
? 'https://www.google-analytics.com/debug/collect'
|
||||
: 'https://www.google-analytics.com/collect';
|
||||
const url = querystring.joinUrl(baseUrl, qs);
|
||||
const url = joinUrlAndQueryString(baseUrl, qs);
|
||||
|
||||
const net = (electron.remote || electron).net;
|
||||
const request = net.request(url);
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -4,7 +4,7 @@ import {Cookie as toughCookie} from 'tough-cookie';
|
||||
import * as models from '../models';
|
||||
import {getRenderedRequest} from './render';
|
||||
import type {RenderedRequest} from './render';
|
||||
import {jarFromCookies} from './cookies';
|
||||
import {jarFromCookies} from 'insomnia-cookies';
|
||||
import * as misc from './misc';
|
||||
import type {Cookie} from '../models/cookie-jar';
|
||||
import {newBodyRaw} from '../models/request';
|
||||
@@ -13,6 +13,7 @@ import type {Response as ResponseModel} from '../models/response';
|
||||
import {getAuthHeader} from '../network/authentication';
|
||||
import {getAppVersion} from './constants';
|
||||
import {RenderError} from '../templating/index';
|
||||
import {smartEncodeUrl} from 'insomnia-url';
|
||||
|
||||
export type HarCookie = {
|
||||
name: string,
|
||||
@@ -288,7 +289,7 @@ export async function exportHarWithRenderedRequest (
|
||||
renderedRequest: RenderedRequest,
|
||||
addContentLength: boolean = false
|
||||
): Promise<HarRequest> {
|
||||
const url = misc.prepareUrlForSending(renderedRequest.url, renderedRequest.settingEncodeUrl);
|
||||
const url = smartEncodeUrl(renderedRequest.url, renderedRequest.settingEncodeUrl);
|
||||
|
||||
if (addContentLength) {
|
||||
const hasContentLengthHeader = misc.filterHeaders(
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,14 +1,12 @@
|
||||
// @flow
|
||||
import * as electron from 'electron';
|
||||
import {Readable, Writable} from 'stream';
|
||||
import {joinUrlAndQueryString} from 'insomnia-url';
|
||||
import uuid from 'uuid';
|
||||
import zlib from 'zlib';
|
||||
import {join as pathJoin} from 'path';
|
||||
import {format as urlFormat, parse as urlParse} from 'url';
|
||||
import {DEBOUNCE_MILLIS, getAppVersion, isDevelopment} from './constants';
|
||||
import * as querystring from './querystring';
|
||||
|
||||
const URL_PATH_CHARACTER_WHITELIST = '+,;@=:';
|
||||
const ESCAPE_REGEX_MATCH = /[-[\]/{}()*+?.\\^$|]/g;
|
||||
|
||||
type Header = {
|
||||
@@ -16,20 +14,6 @@ type Header = {
|
||||
value: string
|
||||
};
|
||||
|
||||
export function getBasicAuthHeader (username: ?string, password: ?string): Header {
|
||||
const name = 'Authorization';
|
||||
const header = `${username || ''}:${password || ''}`;
|
||||
const authString = Buffer.from(header, 'utf8').toString('base64');
|
||||
const value = `Basic ${authString}`;
|
||||
return {name, value};
|
||||
}
|
||||
|
||||
export function getBearerAuthHeader (token: string): Header {
|
||||
const name = 'Authorization';
|
||||
const value = `Bearer ${token}`;
|
||||
return {name, value};
|
||||
}
|
||||
|
||||
export function filterHeaders<T: Header> (headers: Array<T>, name: string): Array<T> {
|
||||
if (!Array.isArray(headers) || !name) {
|
||||
return [];
|
||||
@@ -92,20 +76,6 @@ export function getContentLengthHeader<T: Header> (headers: Array<T>): T | null
|
||||
return matches.length ? matches[0] : null;
|
||||
}
|
||||
|
||||
export function setDefaultProtocol (url: string, defaultProto: string = 'http:'): string {
|
||||
// If no url, don't bother returning anything
|
||||
if (!url) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Default the proto if it doesn't exist
|
||||
if (url.indexOf('://') === -1) {
|
||||
url = `${defaultProto}//${url}`;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an ID of the format "<MODEL_NAME>_<TIMESTAMP><RANDOM>"
|
||||
* @param prefix
|
||||
@@ -121,84 +91,6 @@ export function generateId (prefix: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
export function flexibleEncodeComponent (str: string, ignore: string = ''): string {
|
||||
// Sometimes spaces screw things up because of url.parse
|
||||
str = str.replace(/%20/g, ' ');
|
||||
|
||||
// Handle all already-encoded characters so we don't touch them
|
||||
str = str.replace(/%([0-9a-fA-F]{2})/g, '__ENC__$1');
|
||||
|
||||
// Do a special encode of ignored chars, so they aren't touched.
|
||||
// This first pass, surrounds them with a special tag (anything unique
|
||||
// will work), so it can change them back later
|
||||
// Example: will replace %40 with __LEAVE_40_LEAVE__, and we'll change
|
||||
// it back to %40 at the end.
|
||||
for (const c of ignore) {
|
||||
const code = encodeURIComponent(c).replace('%', '');
|
||||
const re2 = new RegExp(escapeRegex(c), 'g');
|
||||
str = str.replace(re2, `__RAW__${code}`);
|
||||
}
|
||||
|
||||
// Encode it
|
||||
str = encodeURIComponent(str);
|
||||
|
||||
// Put back the raw version of the ignored chars
|
||||
for (const match of str.match(/__RAW__([0-9a-fA-F]{2})/g) || []) {
|
||||
const code = match.replace('__RAW__', '');
|
||||
str = str.replace(match, decodeURIComponent(`%${code}`));
|
||||
}
|
||||
|
||||
// Put back the encoded version of the ignored chars
|
||||
for (const match of str.match(/__ENC__([0-9a-fA-F]{2})/g) || []) {
|
||||
const code = match.replace('__ENC__', '');
|
||||
str = str.replace(match, `%${code}`);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
export function prepareUrlForSending (url: string, autoEncode: boolean = true): string {
|
||||
const urlWithProto = setDefaultProtocol(url);
|
||||
|
||||
if (!autoEncode) {
|
||||
return urlWithProto;
|
||||
} else {
|
||||
// Parse the URL into components
|
||||
const parsedUrl = urlParse(urlWithProto);
|
||||
|
||||
// ~~~~~~~~~~~ //
|
||||
// 1. Pathname //
|
||||
// ~~~~~~~~~~~ //
|
||||
|
||||
if (parsedUrl.pathname) {
|
||||
const segments = parsedUrl.pathname.split('/');
|
||||
parsedUrl.pathname = segments.map(
|
||||
s => flexibleEncodeComponent(s, URL_PATH_CHARACTER_WHITELIST)
|
||||
).join('/');
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~ //
|
||||
// 2. Querystring //
|
||||
// ~~~~~~~~~~~~~~ //
|
||||
|
||||
if (parsedUrl.query) {
|
||||
const qsParams = querystring.deconstructToParams(parsedUrl.query);
|
||||
const encodedQsParams = [];
|
||||
for (const {name, value} of qsParams) {
|
||||
encodedQsParams.push({
|
||||
name: flexibleEncodeComponent(name),
|
||||
value: flexibleEncodeComponent(value)
|
||||
});
|
||||
}
|
||||
|
||||
parsedUrl.query = querystring.buildFromParams(encodedQsParams);
|
||||
parsedUrl.search = `?${parsedUrl.query}`;
|
||||
}
|
||||
|
||||
return urlFormat(parsedUrl);
|
||||
}
|
||||
}
|
||||
|
||||
export function delay (milliseconds: number = DEBOUNCE_MILLIS): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
||||
}
|
||||
@@ -271,7 +163,7 @@ export function attributeHref (href: string): string {
|
||||
if (href.match(/^http/i)) {
|
||||
const appName = isDevelopment() ? 'Insomnia Dev' : 'Insomnia';
|
||||
const qs = `utm_source=${appName}&utm_medium=app&utm_campaign=v${getAppVersion()}`;
|
||||
return querystring.joinUrl(href, qs);
|
||||
return joinUrlAndQueryString(href, qs);
|
||||
} else {
|
||||
// Don't modify non-http urls
|
||||
return href;
|
||||
@@ -2,9 +2,9 @@
|
||||
import type {Request} from '../models/request';
|
||||
import type {BaseModel} from '../models/index';
|
||||
|
||||
import {setDefaultProtocol} from 'insomnia-url';
|
||||
import clone from 'clone';
|
||||
import * as models from '../models';
|
||||
import {setDefaultProtocol} from './misc';
|
||||
import * as db from './database';
|
||||
import * as templating from '../templating';
|
||||
import type {CookieJar} from '../models/cookie-jar';
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -2,7 +2,7 @@
|
||||
import electron from 'electron';
|
||||
import {CHECK_FOR_UPDATES_INTERVAL, getAppVersion, isDevelopment, UPDATE_URL_MAC, UPDATE_URL_WINDOWS} from '../common/constants';
|
||||
import * as models from '../models/index';
|
||||
import * as querystring from '../common/querystring';
|
||||
import {buildQueryStringFromParams, joinUrlAndQueryString} from 'insomnia-url';
|
||||
import {delay} from '../common/misc';
|
||||
|
||||
const {autoUpdater, BrowserWindow, ipcMain} = electron;
|
||||
@@ -25,8 +25,8 @@ async function getUpdateUrl (force: boolean): Promise<string | null> {
|
||||
{name: 'channel', value: settings.updateChannel}
|
||||
];
|
||||
|
||||
const qs = querystring.buildFromParams(params);
|
||||
const fullUrl = querystring.joinUrl(updateUrl, qs);
|
||||
const qs = buildQueryStringFromParams(params);
|
||||
const fullUrl = joinUrlAndQueryString(updateUrl, qs);
|
||||
console.log(`[updater] Using url ${fullUrl}`);
|
||||
|
||||
if (isDevelopment()) {
|
||||
@@ -96,7 +96,7 @@ export function createWindow () {
|
||||
});
|
||||
|
||||
// Load the html of the app.
|
||||
const appUrl = process.env.APP_RENDER_URL || `file://${__dirname}/renderer.html`;
|
||||
const appUrl = process.env.APP_RENDER_URL || `file://${app.getAppPath()}/renderer.html`;
|
||||
console.log(`[main] Loading ${process.env.APP_RENDER_URL}`);
|
||||
mainWindow.loadURL(appUrl);
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 957 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user