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

Commit

Permalink
feat: Added typescript support!
Browse files Browse the repository at this point in the history
  • Loading branch information
harazdovskiy committed Aug 9, 2022
1 parent f59e20c commit b073618
Show file tree
Hide file tree
Showing 15 changed files with 199 additions and 50 deletions.
2 changes: 2 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
steps:
- checkout
- run: yarn
- run: yarn build
- run: yarn test

test_with_db:
Expand All @@ -20,6 +21,7 @@ jobs:
steps:
- checkout
- run: yarn
- run: yarn build
- run: yarn test

workflows:
Expand Down
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
lib/
renovate.json
tsconfig.json
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.idea/
coverage/
node_modules/
lib/
temp
yarn.lock
*.log
Expand Down
7 changes: 6 additions & 1 deletion jest-dynamodb-config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
module.exports = {
/**
* @type {import('./lib/types').Config}
*/
const config = {
tables: [
{
TableName: `files`,
Expand All @@ -16,3 +19,5 @@ module.exports = {
port: 8000,
options: ['-sharedDb'],
};

module.exports = config;
8 changes: 2 additions & 6 deletions jest-preset.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
const {resolve} = require('path');
const preset = require('./lib');

module.exports = {
globalSetup: resolve(__dirname, './setup.js'),
globalTeardown: resolve(__dirname, './teardown.js'),
testEnvironment: resolve(__dirname, './environment.js'),
};
module.exports = preset;
25 changes: 19 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,29 @@
"url": "shelf.io"
},
"files": [
"environment.js",
"src/environment.js",
"jest-preset.js",
"setup.js",
"teardown.js",
"wait-for-localhost.js"
"src/setup.js",
"src/teardown.js",
"src/index.d.ts",
"src/utils/wait-for-localhost.js"
],
"scripts": {
"build": "rm -rf lib/ && yarn build:types && babel src --out-dir lib --ignore '**/*.test.ts' --extensions '.ts'",
"build:types": "tsc --emitDeclarationOnly --declaration --isolatedModules false --declarationDir lib",
"coverage": "jest --coverage",
"lint": "eslint . --ext .js,.ts,.json --fix",
"lint:ci": "eslint . --ext .js,.ts,.json",
"test": "export ENVIRONMENT=local && jest ."
"prepack": "yarn build",
"test": "export ENVIRONMENT=local && jest tests",
"type-check": "tsc --noEmit",
"type-check:watch": "npm run type-check -- --watch"
},
"lint-staged": {
"*.{html,md,yml}": [
"prettier --write"
],
"*.{js,json}": [
"*.{ts,js,json}": [
"eslint --fix"
]
},
Expand All @@ -53,9 +59,16 @@
"dynamodb-local": "0.0.31"
},
"devDependencies": {
"@babel/cli": "7.18.9",
"@babel/core": "7.18.9",
"@shelf/babel-config": "1.0.2",
"@shelf/eslint-config": "2.18.0",
"@shelf/prettier-config": "1.0.0",
"@shelf/tsconfig": "0.0.8",
"@types/aws-sdk": "2.7.0",
"@types/cwd": "^0.10.0",
"@types/jest": "28.1.6",
"@types/node": "16",
"eslint": "8.20.0",
"husky": "8.0.1",
"jest": "28.1.3",
Expand Down
11 changes: 8 additions & 3 deletions environment.js → src/environment.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
/* eslint-disable no-console */
const {TestEnvironment} = require('jest-environment-node');
import type {EnvironmentContext} from '@jest/environment';
import type {JestEnvironmentConfig} from '@jest/environment';
import {TestEnvironment} from 'jest-environment-node';

const debug = require('debug')('jest-dynamodb');

module.exports = class DynamoDBEnvironment extends TestEnvironment {
constructor(config) {
super(config);
constructor(config: JestEnvironmentConfig, context: EnvironmentContext) {
super(config, context);
}

async setup() {
Expand All @@ -19,7 +22,9 @@ module.exports = class DynamoDBEnvironment extends TestEnvironment {
await super.teardown();
}

// @ts-ignore
runScript(script) {
// @ts-ignore
return super.runScript(script);
}
};
9 changes: 9 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {resolve} from 'path';

export * from './types';

export default {
globalSetup: resolve(__dirname, './setup.js'),
globalTeardown: resolve(__dirname, './teardown.js'),
testEnvironment: resolve(__dirname, './environment.js'),
};
46 changes: 31 additions & 15 deletions setup.js → src/setup.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
const {resolve} = require('path');
const cwd = require('cwd');
const {DynamoDB} = require('@aws-sdk/client-dynamodb');
const DynamoDbLocal = require('dynamodb-local');
import type {ListTablesCommandOutput} from '@aws-sdk/client-dynamodb/dist-types/commands/ListTablesCommand';
import type {argValues} from 'dynamodb-local';
import DynamoDbLocal from 'dynamodb-local';
import {resolve} from 'path';
import cwd from 'cwd';
import {DynamoDB} from '@aws-sdk/client-dynamodb';
import type {CreateTableCommandInput} from '@aws-sdk/client-dynamodb';
import type {Config} from './types';
import waitForLocalhost from './utils/wait-for-localhost';

const debug = require('debug')('jest-dynamodb');
const waitForLocalhost = require('./wait-for-localhost');

const DEFAULT_PORT = 8000;
const DEFAULT_OPTIONS = ['-sharedDb'];
const DEFAULT_OPTIONS: argValues[] = ['-sharedDb'];

module.exports = async function () {
const config = require(process.env.JEST_DYNAMODB_CONFIG ||
resolve(cwd(), 'jest-dynamodb-config.js'));
debug('config:', config);
const {
tables: newTables,
clientConfig,
installerConfig,
port: port = DEFAULT_PORT,
options: options = DEFAULT_OPTIONS,
} = typeof config === 'function' ? await config() : config;
} = await getConfig();

const dynamoDB = new DynamoDB({
endpoint: `http://localhost:${port}`,
Expand All @@ -34,14 +36,20 @@ module.exports = async function () {
global.__DYNAMODB_CLIENT__ = dynamoDB;

try {
const promises = [dynamoDB.listTables({})];
const promises: (Promise<ListTablesCommandOutput> | Promise<void>)[] = [
dynamoDB.listTables({}),
];

if (!global.__DYNAMODB__) {
promises.push(waitForLocalhost(port));
}

const [{TableNames: tableNames}] = await Promise.all(promises);
await deleteTables(dynamoDB, tableNames); // cleanup leftovers
const [TablesList] = await Promise.all(promises);
const tableNames = TablesList?.TableNames;

if (tableNames) {
await deleteTables(dynamoDB, tableNames);
}
} catch (err) {
// eslint-disable-next-line no-console
debug(`fallback to launch DB due to ${err}`);
Expand All @@ -64,10 +72,18 @@ module.exports = async function () {
await createTables(dynamoDB, newTables);
};

function createTables(dynamoDB, tables) {
function createTables(dynamoDB: DynamoDB, tables: CreateTableCommandInput[]) {
return Promise.all(tables.map(table => dynamoDB.createTable(table)));
}

function deleteTables(dynamoDB, tableNames) {
function deleteTables(dynamoDB: DynamoDB, tableNames: string[]) {
return Promise.all(tableNames.map(tableName => dynamoDB.deleteTable({TableName: tableName})));
}

async function getConfig(): Promise<Config> {
const path = process.env.JEST_DYNAMODB_CONFIG || resolve(cwd(), 'jest-dynamodb-config.js');
const config = require(path);
debug('config:', config);

return typeof config === 'function' ? await config() : config;
}
11 changes: 8 additions & 3 deletions teardown.js → src/teardown.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const DynamoDbLocal = require('dynamodb-local');
import DynamoDbLocal from 'dynamodb-local';
import type {JestArgs} from './types';

const debug = require('debug')('jest-dynamodb');

module.exports = async function (jestArgs) {
module.exports = async function (jestArgs: JestArgs) {
// eslint-disable-next-line no-console
debug('Teardown DynamoDB');

Expand All @@ -14,6 +16,9 @@ module.exports = async function (jestArgs) {
} else {
const dynamoDB = global.__DYNAMODB_CLIENT__;
const {TableNames: tableNames} = await dynamoDB.listTables({});
await Promise.all(tableNames.map(tableName => dynamoDB.deleteTable({TableName: tableName})));

if (tableNames && tableNames.length) {
await Promise.all(tableNames.map(tableName => dynamoDB.deleteTable({TableName: tableName})));
}
}
};
86 changes: 86 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* eslint-disable */
import type {DynamoDB} from '@aws-sdk/client-dynamodb';
import type {CreateTableCommandInput} from '@aws-sdk/client-dynamodb';
import type {DynamoDBClientConfig} from '@aws-sdk/client-dynamodb';
import type {ChildProcess} from 'child_process';
import type {InstallerConfig} from 'dynamodb-local';
import type {argValues} from 'dynamodb-local';

declare global {
var __DYNAMODB_CLIENT__: DynamoDB;
var __DYNAMODB__: ChildProcess;
}

export type JestArgs = {
bail: number;
changedSince?: string;
changedFilesWithAncestor: boolean;
ci: boolean;
collectCoverage: boolean;
collectCoverageFrom: Array<string>;
collectCoverageOnlyFrom?: {
[key: string]: boolean;
};
coverageDirectory: string;
coveragePathIgnorePatterns?: Array<string>;
coverageProvider: object;
coverageReporters: object;
coverageThreshold?: object;
detectLeaks: boolean;
detectOpenHandles: boolean;
expand: boolean;
filter?: string;
findRelatedTests: boolean;
forceExit: boolean;
json: boolean;
globalSetup?: string;
globalTeardown?: string;
lastCommit: boolean;
logHeapUsage: boolean;
listTests: boolean;
maxConcurrency: number;
maxWorkers: number;
noStackTrace: boolean;
nonFlagArgs: Array<string>;
noSCM?: boolean;
notify: boolean;
notifyMode: object;
outputFile?: string;
onlyChanged: boolean;
onlyFailures: boolean;
passWithNoTests: boolean;
projects: Array<string>;
replname?: string;
reporters?: Array<object>;
runTestsByPath: boolean;
rootDir: string;
shard?: object;
silent?: boolean;
skipFilter: boolean;
snapshotFormat: object;
errorOnDeprecated: boolean;
testFailureExitCode: number;
testNamePattern?: string;
testPathPattern: string;
testResultsProcessor?: string;
testSequencer: string;
testTimeout?: number;
updateSnapshot: object;
useStderr: boolean;
verbose?: boolean;
watch: boolean;
watchAll: boolean;
watchman: boolean;
watchPlugins?: Array<{
path: string;
config: Record<string, unknown>;
}> | null;
};

export type Config = {
tables: CreateTableCommandInput[];
clientConfig?: DynamoDBClientConfig;
installerConfig: InstallerConfig;
port: number;
options: argValues[];
};
24 changes: 12 additions & 12 deletions wait-for-localhost.js → src/utils/wait-for-localhost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@

const http = require('http');

const waitForLocalhost = port =>
new Promise(resolve => {
export default function waitForLocalhost(port: number): Promise<void> {
return new Promise<void>(resolve => {
const retry = () => setTimeout(main, 200);

const main = () => {
const request = http.request({method: 'GET', port, path: '/'}, response => {
if (response.statusCode === 400) {
return resolve();
}
const request = http.request(
{method: 'GET', port, path: '/'},
(response: {statusCode: number}) => {
if (response.statusCode === 400) {
return resolve();
}

retry();
});
retry();
}
);

request.on('error', retry);
request.end();
};

main();
});

module.exports = waitForLocalhost;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const {DynamoDB} = require('@aws-sdk/client-dynamodb');
const {DynamoDBDocument} = require('@aws-sdk/lib-dynamodb');
import {DynamoDB} from '@aws-sdk/client-dynamodb';
import {DynamoDBDocument} from '@aws-sdk/lib-dynamodb';

const ddb = DynamoDBDocument.from(
new DynamoDB({
Expand Down
4 changes: 2 additions & 2 deletions index.test.js → tests/jest-preset.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const {DynamoDB} = require('@aws-sdk/client-dynamodb');
const {DynamoDBDocument} = require('@aws-sdk/lib-dynamodb');
import {DynamoDB} from '@aws-sdk/client-dynamodb';
import {DynamoDBDocument} from '@aws-sdk/lib-dynamodb';

const ddb = DynamoDBDocument.from(
new DynamoDB({
Expand Down
8 changes: 8 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "@shelf/tsconfig/backend",
"compilerOptions": {
"strict": true
},
"exclude": ["node_modules"],
"include": ["src"]
}

0 comments on commit b073618

Please sign in to comment.