Skip to content

Commit

Permalink
Feature/create route from proxy response 139 (#185)
Browse files Browse the repository at this point in the history
- Creating route from environment log (proxied and normal) #139
- Styling mock button
- Writing tests for proxy mock and basic mock
  • Loading branch information
gabrielperes97 authored and 255kb committed Oct 23, 2019
1 parent 56741f6 commit bdecf7a
Show file tree
Hide file tree
Showing 12 changed files with 276 additions and 9 deletions.
5 changes: 5 additions & 0 deletions src/app/components/environment-logs.component.html
Expand Up @@ -15,6 +15,11 @@
</div>
<div class="ellipsis">{{log.url}}</div>
</div>
<div>
<button type="button" class="btn btn-link btn-icon btn-mock" (click)="createRouteFromLog(log.uuid)">
<i class="material-icons" ngbTooltip="Mock">control_point_duplicate</i>
</button>
</div>
<div>
<span *ngIf="log.route" class="float-right text-success">
<i class="material-icons" ngbTooltip="Request caught">check</i>
Expand Down
5 changes: 5 additions & 0 deletions src/app/components/environment-logs.component.scss
Expand Up @@ -42,4 +42,9 @@ $logs-border: 1px solid lighten($gray-900, 1%);
}
}
}

.btn-mock {
padding: 0;
margin: 0 10px 0 0;
}
}
4 changes: 4 additions & 0 deletions src/app/components/environment-logs.component.ts
Expand Up @@ -71,4 +71,8 @@ export class EnvironmentLogsComponent implements OnInit {
public setActiveTab(tabName: EnvironmentLogsTabsNameType) {
this.environmentsService.setActiveEnvironmentLogTab(tabName);
}

public createRouteFromLog(logUuid: string) {
this.environmentsService.createRouteFromLog(logUuid);
}
}
6 changes: 4 additions & 2 deletions src/app/enums/analytics-events.enum.ts
Expand Up @@ -6,7 +6,8 @@ type AnalyticsEventsNames =
'CREATE_ENVIRONMENT' | 'CREATE_ROUTE' | 'CREATE_ROUTE_RESPONSE' | 'CREATE_HEADER' | 'DUPLICATE_ENVIRONMENT' |
'DUPLICATE_ROUTE' | 'DELETE_ENVIRONMENT' | 'DELETE_ROUTE' | 'DELETE_ROUTE_RESPONSE' | 'DELETE_HEADER' |
'LINK_ROUTE_IN_BROWSER' | 'LINK_FEEDBACK' | 'LINK_RELEASE' | 'LINK_WIKI' | 'LINK_APPLY_UPDATE' |
'EXPORT_FILE' | 'EXPORT_CLIPBOARD' | 'IMPORT_FILE' | 'IMPORT_CLIPBOARD' | 'SERVER_ENTERING_REQUEST';
'EXPORT_FILE' | 'EXPORT_CLIPBOARD' | 'IMPORT_FILE' | 'IMPORT_CLIPBOARD' | 'SERVER_ENTERING_REQUEST' |
'CREATE_ROUTE_FROM_LOG';

export const AnalyticsEvents: { [keyof in AnalyticsEventsNames]: CollectParams } = {
PAGEVIEW: { type: 'pageview', pageName: '/' },
Expand Down Expand Up @@ -36,5 +37,6 @@ export const AnalyticsEvents: { [keyof in AnalyticsEventsNames]: CollectParams }
EXPORT_CLIPBOARD: { type: 'event', category: 'export', action: 'clipboard' },
IMPORT_FILE: { type: 'event', category: 'import', action: 'file' },
IMPORT_CLIPBOARD: { type: 'event', category: 'import', action: 'clipboard' },
SERVER_ENTERING_REQUEST: { type: 'event', category: 'server', action: 'entering-request' }
SERVER_ENTERING_REQUEST: { type: 'event', category: 'server', action: 'entering-request' },
CREATE_ROUTE_FROM_LOG: { type: 'event', category: 'create', action: 'route-from-log' },
};
57 changes: 56 additions & 1 deletion src/app/services/environments.service.ts
Expand Up @@ -19,9 +19,10 @@ import { ReducerDirectionType } from 'src/app/stores/reducer';
import { EnvironmentLogsTabsNameType, Store, TabsNameType, ViewsNameType } from 'src/app/stores/store';
import { DataSubjectType, ExportType } from 'src/app/types/data.type';
import { Environment, EnvironmentProperties, Environments } from 'src/app/types/environment.type';
import { CORSHeaders, Header, Route, RouteProperties, RouteResponse, RouteResponseProperties } from 'src/app/types/route.type';
import { CORSHeaders, Header, Route, RouteProperties, RouteResponse, RouteResponseProperties, Method } from 'src/app/types/route.type';
import { dragulaNamespaces } from 'src/app/types/ui.type';
import * as uuid from 'uuid/v1';
import { RouteResponseRulesComponent } from '../components/route-response-rules.component';
const appVersion = require('../../../package.json').version;

@Injectable()
Expand Down Expand Up @@ -643,4 +644,58 @@ export class EnvironmentsService {
public setEnvironmentCORSHeaders() {
this.eventsService.injectHeaders.emit({ target: 'environmentHeaders', headers: CORSHeaders });
}

/**
* Create a route based on a environment log entry
*/
public createRouteFromLog(logUUID?: string) {
const environmentsLogs = this.store.get('environmentsLogs');
const uuidEnvironment = this.store.get('activeEnvironmentUUID');
const log = environmentsLogs[uuidEnvironment].find(environmentLog => environmentLog.uuid === logUUID);

if (log) {
let response: RouteResponse;
if (log.response) {
const headers: Header[] = [];
log.response.headers.forEach(element => {
headers.push({
key: element.name,
value: element.value
});
});
response = {
headers: headers,
statusCode: log.response.status.toString(),
body: log.response.body,
rules: [],
latency: 0,
sendFileAsBody: false,
filePath: null,
uuid: uuid()
};
} else {
response = {
headers: [],
statusCode: '200',
body: '{}',
rules: [],
latency: 0,
sendFileAsBody: false,
filePath: null,
uuid: uuid()
};
}

const newRoute: Route = {
uuid: uuid(),
documentation: '',
method: log.method.toLowerCase() as Method,
endpoint: log.url.slice(1), // Remove the initial slash '/'
responses: [response],
};
this.store.update(addRouteAction(newRoute));

this.eventsService.analyticsEvents.next(AnalyticsEvents.CREATE_ROUTE_FROM_LOG);
}
}
}
4 changes: 3 additions & 1 deletion src/app/types/route.type.ts
Expand Up @@ -255,7 +255,7 @@ export type ResponseRuleTargets = 'body' | 'query' | 'header' | 'params';
export type Route = {
uuid: string;
documentation: string;
method: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head';
method: Method;
endpoint: string;
responses: RouteResponse[];
};
Expand All @@ -271,3 +271,5 @@ export const CORSHeaders: Header[] = [
export type RouteProperties = { [T in keyof Route]?: Route[T] };

export type RouteResponseProperties = { [T in keyof RouteResponse]?: RouteResponse[T] };

export type Method = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head';
107 changes: 107 additions & 0 deletions test/data/proxy/environments.json
@@ -0,0 +1,107 @@
[
{
"uuid": "323a25c6-b196-4d27-baf8-8aeb83d87c76",
"name": "FT env",
"endpointPrefix": "",
"latency": 0,
"port": 3000,
"routes": [
{
"uuid": "dd07b407-df1f-4393-83f2-7a832fdd6f99",
"method": "get",
"endpoint": "*/:var/a(b)?c/[0-9]{1,5}",
"documentation": "Test documentation",
"responses": [
{
"uuid": "505a77b1-34c7-4af8-adde-ed00b8dd29bf",
"body": "{\"response\": \"{{urlParam 'var'}}\"}",
"latency": 0,
"statusCode": "200",
"headers": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"filePath": "",
"sendFileAsBody": false,
"rules": []
}
]
},
{
"uuid": "9745a08e-94c2-451e-bccc-b31dc608bb6d",
"method": "get",
"endpoint": "answer",
"documentation": "",
"responses": [
{
"uuid": "057ec98a-dd5d-4dd8-9af9-a99dd7a5c3f5",
"body": "42",
"latency": 0,
"statusCode": "200",
"headers": [
{
"key": "Content-Type",
"value": "text/plain"
}
],
"filePath": "",
"sendFileAsBody": false,
"rules": []
}
]
},
{
"uuid": "9eec44ab-48b1-454f-8cda-ddbc9aeaac0e",
"method": "post",
"endpoint": "dolphins",
"documentation": "",
"responses": [
{
"uuid": "6d3abb6f-6705-4588-8b09-337ddc4ae33c",
"body": "{\n \"response\": \"So Long, and Thanks for All the Fish\"\n}",
"latency": 0,
"statusCode": "200",
"headers": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"filePath": "",
"sendFileAsBody": false,
"rules": []
}
]
}
],
"proxyMode": false,
"proxyHost": "",
"https": false,
"cors": true,
"headers": [
{
"key": "",
"value": ""
}
]
}, {
"uuid": "2cbdec80-f284-11e9-a28c-912bdc671019",
"name": "Proxy",
"endpointPrefix": "",
"latency": 0,
"port": 3001,
"routes": [],
"proxyMode": true,
"proxyHost": "http://127.0.0.1:3000",
"https": false,
"cors": true,
"headers": [
{
"key": "Content-Type",
"value": "application/json"
}
]
}
]
5 changes: 5 additions & 0 deletions test/data/proxy/settings.json
@@ -0,0 +1,5 @@
{
"welcomeShown": true,
"analytics": true,
"lastMigration": 6
}
6 changes: 6 additions & 0 deletions test/environment-logs.spec.ts
Expand Up @@ -63,4 +63,10 @@ describe('Environment logs', () => {
await tests.spectron.client.element('.environment-logs-content .nav .nav-item:nth-child(1)').click();
await tests.spectron.client.getText('.environment-logs-content-request > div:nth-child(2) > div:nth-child(1)').should.eventually.equal('Request URL: /test');
});

it('Mock /test log', async () => {
await tests.helpers.countRoutes(3);
await tests.spectron.client.element(`${environmentLogsItemSelector}:nth-child(1) .btn-mock`).click();
await tests.helpers.countRoutes(4);
})
});
24 changes: 21 additions & 3 deletions test/lib/helpers.ts
Expand Up @@ -39,6 +39,11 @@ export class Helpers {
.should.eventually.have.property('value').to.be.an('Array').that.have.lengthOf(expected);
}

async countEnvironmentLogsEntries(expected: number) {
await this.testsInstance.spectron.client.elements('.environment-logs-column:nth-child(1) .menu-list .nav-item')
.should.eventually.have.property('value').to.be.an('Array').that.have.lengthOf(expected);
}

async contextMenuClickAndConfirm(targetMenuItemSelector: string, contextMenuItemIndex: number) {
await this.testsInstance.spectron.client.element(targetMenuItemSelector).rightClick();

Expand All @@ -49,7 +54,16 @@ export class Helpers {

async startEnvironment() {
await this.testsInstance.spectron.client.element('.btn i[ngbtooltip="Start server"]').click();
await this.testsInstance.spectron.client.waitForExist(`.menu-column--environments .menu-list .nav-item .nav-link.running`);
await this.testsInstance.spectron.client.waitForExist(`.menu-column--environments .menu-list .nav-item .nav-link.active.running`);
}

async stopEnvironment() {
await this.testsInstance.spectron.client.element('.btn i[ngbtooltip="Stop server"]').click();
await this.testsInstance.spectron.client.waitForExist(`.menu-column--environments .menu-list .nav-item .nav-link.active.running`, 1000, true);
}

async selectEnvironment(index: number) {
await this.testsInstance.spectron.client.element(`.menu-column--environments .menu-list .nav-item:nth-child(${index}) .nav-link`).click();
}

async setRouteStatusCode(statusCode: string) {
Expand Down Expand Up @@ -91,10 +105,10 @@ export class Helpers {
await this.testsInstance.spectron.client.element('app-route-response-rules .row:last-of-type .form-inline input[formcontrolname="value"]').setValue(rule.value);
}

async httpCallAsserter(httpCall: HttpCall) {
async httpCallAsserterWithPort(httpCall: HttpCall, port: number) {
await fetch({
protocol: 'http',
port: 3000,
port: port,
path: httpCall.path,
method: httpCall.method,
headers: httpCall.headers,
Expand All @@ -105,4 +119,8 @@ export class Helpers {
}, {})
);
}

async httpCallAsserter(httpCall: HttpCall) {
await this.httpCallAsserterWithPort(httpCall, 3000);
}
}
59 changes: 59 additions & 0 deletions test/proxy.spec.ts
@@ -0,0 +1,59 @@
import { Tests } from './lib/tests';
import { HttpCall } from './lib/types';

const tests = new Tests('proxy');

const getAnswerCall: HttpCall = {
description: 'Call GET answer',
path: '/answer',
method: 'GET',
testedProperties: {
body: '42',
status: 200
}
};

const environmentLogsItemSelector = '.environment-logs-column:nth-child(1) .menu-list .nav-item';

describe('Proxy', () => {
tests.runHooks();

it('Start environments', async () => {
await tests.helpers.startEnvironment();
await tests.helpers.selectEnvironment(2);
await tests.helpers.startEnvironment();
});

it ('Call /anwser', async () => {
await tests.helpers.httpCallAsserterWithPort(getAnswerCall, 3001);
});

it('Environment logs have one entry', async () => {
await tests.helpers.switchViewInHeader('ENV_LOGS');
await tests.helpers.countEnvironmentLogsEntries(1);
});

it('First entry is GET /answer and was proxied by the application', async () => {
await tests.spectron.client.getText(`${environmentLogsItemSelector}:nth-child(1) .nav-link .route`).should.eventually.equal('GET\n/answer');
await tests.spectron.client.waitForExist(`${environmentLogsItemSelector}:nth-child(1) .nav-link i[ngbTooltip="Request proxied"]`, 5000, false);
});

it('Click on mock button ', async () => {
await tests.spectron.client.element(`${environmentLogsItemSelector}:nth-child(1) .btn-mock`).click();
await tests.helpers.stopEnvironment();
await tests.helpers.startEnvironment();
});

it('Check route added', async () => {
await tests.helpers.countRoutes(1);
});

it('Test new mock', async () => {
await tests.helpers.httpCallAsserterWithPort(getAnswerCall, 3001);
await tests.helpers.switchViewInHeader('ENV_LOGS');
await tests.helpers.countEnvironmentLogsEntries(2);
await tests.spectron.client.getText(`${environmentLogsItemSelector}:nth-child(1) .nav-link .route`).should.eventually.equal('GET\n/answer');
await tests.spectron.client.waitForExist(`${environmentLogsItemSelector}:nth-child(1) .nav-link i[ngbTooltip="Request proxied"]`, 5000, true);
});

});
3 changes: 1 addition & 2 deletions test/server-start.spec.ts
Expand Up @@ -10,7 +10,6 @@ describe('Environment start/stop/restart', () => {
});

it('Stop default selected environment', async () => {
await tests.spectron.client.element('.btn i[ngbtooltip="Stop server"]').click();
await tests.spectron.client.waitForExist('.menu-column--environments .menu-list .nav-item .nav-link.running', 5000, true);
await tests.helpers.stopEnvironment();
});
});

0 comments on commit bdecf7a

Please sign in to comment.