Skip to content
This repository has been archived by the owner on Nov 8, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1545 from apiaryio/ts-port-01
Browse files Browse the repository at this point in the history
Rewrites simple modules to TypeScript
  • Loading branch information
artem-zakharchenko authored Oct 22, 2019
2 parents 4d0595f + 875fc45 commit ddcc77e
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 55 deletions.
82 changes: 82 additions & 0 deletions packages/dredd/lib/general.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
export enum HTTPMethod {
CONNECT = 'CONNECT',
OPTIONS = 'OPTIONS',
POST = 'POST',
GET = 'GET',
HEAD = 'HEAD',
PUT = 'PUT',
PATCH = 'PATCH',
DELETE = 'DELETE',
TRACE = 'TRACE',
}

export enum BodyEncoding {
'utf-8',
'base64',
}

export enum TransactionTestStatus {
'pass',
'fail',
'skip',
}

export interface Transaction {
id: string;
name: string;
origin: TransactionOrigin;
host: string;
port: number;
protocol: 'http:' | 'https:';
fullPath: string;
request: TransactionRequest;
expected: {
statusCode: number;
headers: Record<string, string>;
body: string;
bodySchema: Record<string, any>;
};
real: {
statusCode: string;
headers: Record<string, string>;
body: string;
bodyEncoding: BodyEncoding;
};
skip: boolean;
fail: boolean;

test: TransactionTest;
}

export interface TransactionRequest {
method: HTTPMethod;
url: string;
body?: string;
bodyEncoding?: BodyEncoding;
headers?: Record<string, string>;
}

export interface TransactionOrigin {
filename: string;
apiName: string;
resourceGroupName: string;
resourceName: string;
actionName: string;
exampleName: string;
}

export interface TransactionTest {
start: Date;
end: Date;
duration: number;
startedAt: number;
title: string;
request: TransactionRequest;
actual: any;
expected: any;
status: TransactionTestStatus;
message: string;
results: any;
valid: boolean;
origin: TransactionOrigin;
}
4 changes: 1 addition & 3 deletions packages/dredd/lib/isURL.js → packages/dredd/lib/isURL.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/**
* Decides whether given string is a URL or not
* @param {string} location
* @returns {boolean}
*/
export default function isURL(location) {
export default function isURL(location: string): boolean {
return /^http(s)?:\/\//.test(location);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,18 @@ import isURL from './isURL';
*
* Keeps URLs intact. Keeps the original order. Throws in case there's a glob
* pattern which doesn't resolve to any existing files.
*
* @param {string} workingDirectory
* @param {string[]} locations
* @returns {string[]}
*/
export default function resolveLocations(workingDirectory, locations) {
export default function resolveLocations(
workingDirectory: string,
locations: string[],
): string[] {
const resolvedLocations = locations
// resolves paths to local files, produces an array of arrays
.map((location) =>
isURL(location) ? [location] : resolvePaths(workingDirectory, [location]),
)
// flattens the array of arrays
.reduce((flatArray, array) => flatArray.concat(array), []);
.reduce<string[]>((flatArray, array) => flatArray.concat(array), []);

return Array.from(new Set(resolvedLocations));
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import fs from 'fs';
import path from 'path';

export default function resolveModule(workingDirectory, moduleName) {
export default function resolveModule(
workingDirectory: string,
moduleName: string,
): string {
const absolutePath = path.resolve(workingDirectory, moduleName);
return fs.existsSync(absolutePath) || fs.existsSync(`${absolutePath}.js`)
? absolutePath
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import glob from 'glob';
const basename =
process.platform === 'win32' ? path.win32.basename : path.basename;

function resolveGlob(workingDirectory, pattern) {
function resolveGlob(workingDirectory: string, pattern: string): string[] {
// 'glob.sync()' does not resolve paths, only glob patterns
if (glob.hasMagic(pattern)) {
return glob
Expand All @@ -23,7 +23,10 @@ function resolveGlob(workingDirectory, pattern) {
* Resolves glob patterns and sorts the files alphabetically by their basename.
* Throws in case there's a pattern which doesn't resolve to any existing files.
*/
export default function resolvePaths(workingDirectory, patterns) {
export default function resolvePaths(
workingDirectory: string,
patterns: string[],
) {
if (!patterns || patterns.length < 1) {
return [];
}
Expand Down
42 changes: 0 additions & 42 deletions packages/dredd/lib/sortTransactions.js

This file was deleted.

61 changes: 61 additions & 0 deletions packages/dredd/lib/sortTransactions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { HTTPMethod, Transaction } from './general';

const sortedMethods: HTTPMethod[] = [
HTTPMethod.CONNECT,
HTTPMethod.OPTIONS,
HTTPMethod.POST,
HTTPMethod.GET,
HTTPMethod.HEAD,
HTTPMethod.PUT,
HTTPMethod.PATCH,
HTTPMethod.DELETE,
HTTPMethod.TRACE,
];

// Often, API description is arranged with a sequence of methods that lends
// itself to understanding by the human reading the documentation.
//
// However, the sequence of methods may not be appropriate for the machine
// reading the documentation in order to test the API.
//
// By sorting the transactions by their methods, it is possible to ensure that
// objects are created before they are read, updated, or deleted.
export default function sortTransactions(
transactions: Transaction[],
): Transaction[] {
// Convert the list of transactions into a list of tuples
// that hold each trasnaction index and details.
const tempTransactions: Array<[number, Transaction]> = transactions.map(
(transaction, index) => [index, transaction],
);

tempTransactions.sort(
([leftIndex, leftTransaction], [rightIndex, rightTransaction]) => {
const methodIndexA = sortedMethods.indexOf(
leftTransaction.request.method,
);
const methodIndexB = sortedMethods.indexOf(
rightTransaction.request.method,
);

// Sort transactions according to the transaction's request method
if (methodIndexA < methodIndexB) {
return -1;
}

if (methodIndexA > methodIndexB) {
return 1;
}

// In case two transactions' request methods are the same,
// preserve the original order of those transactions
return leftIndex - rightIndex;
},
);

const cleanTransactions = tempTransactions.map(
([_, transaction]) => transaction,
);

return cleanTransactions;
}
3 changes: 2 additions & 1 deletion packages/dredd/test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"target": "esnext",
"allowSyntheticDefaultImports": true,
"allowJs": true,
"noEmit": true
"noEmit": true,
"rootDir": "../"
},
"include": ["./**/*.ts"]
}
104 changes: 104 additions & 0 deletions packages/dredd/test/unit/sortTransactions-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import R from 'ramda';
import { expect } from 'chai';
import sortTransactions from '../../lib/sortTransactions';
import { Transaction, HTTPMethod } from '../../lib/general';

const createTransaction = (transaction: Partial<Transaction>) => {
return R.mergeDeepRight<Partial<Transaction>>({
protocol: 'http:',
host: 'localhost',
})(transaction);
};

const transactions = Object.keys(HTTPMethod).reduce<
Record<HTTPMethod, Transaction>
>(
(acc, method: HTTPMethod) => {
return R.assoc(
method,
createTransaction({
request: {
url: '/endpoint',
method,
},
}),
acc,
);
},
{} as any,
);

describe('sortTransactions', () => {
describe('given transactions list in arbitrary order', () => {
const sorted = sortTransactions([
transactions.GET,
transactions.TRACE,
transactions.OPTIONS,
transactions.HEAD,
transactions.DELETE,
transactions.POST,
transactions.PATCH,
transactions.PUT,
transactions.CONNECT,
]);

it('should return transactions list sorted', () => {
expect(sorted).to.deep.equal([
transactions.CONNECT,
transactions.OPTIONS,
transactions.POST,
transactions.GET,
transactions.HEAD,
transactions.PUT,
transactions.PATCH,
transactions.DELETE,
transactions.TRACE,
]);
});
});

describe('given multiple transactions with the same method', () => {
const getOne = createTransaction({
id: 'one',
request: {
method: HTTPMethod.GET,
url: '/endpoint',
},
});

const getTwo = createTransaction({
id: 'two',
request: {
method: HTTPMethod.GET,
url: '/endpoint',
},
});

// This doesn't assert the identity of transactions.
const sorted = sortTransactions([getOne as any, getTwo]);

it('should sort transactions by occurence (asc)', () => {
expect(sorted).to.deep.equal([getOne, getTwo]);
});
});

describe('given transactions list sorted properly', () => {
const transactionsList = [
transactions.CONNECT,
transactions.OPTIONS,
transactions.POST,
transactions.POST,
transactions.GET,
transactions.HEAD,
transactions.PUT,
transactions.PATCH,
transactions.DELETE,
transactions.TRACE,
];
const sorted = sortTransactions(transactionsList);

it('should return transactions list as-is', () => {
expect(sorted).to.deep.equal(transactionsList);
});
});
});

0 comments on commit ddcc77e

Please sign in to comment.