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

Rewrites simple modules to TypeScript #1545

Merged
merged 9 commits into from
Oct 22, 2019
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;
}
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';

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a similar test written in JS being removed. Does it mean you want to keep it to be sure nothing got broken, or that it doesn't exist and this part isn't tested?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find any existing test that would cover sortTransactions. To my knowledge this adds the missing unit test, so there is no JavaScript predecessor to remove. Please, point me if you know where this behavior may be tested already. Thanks.

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);
});
});
});