Enable ESLint & TS for smoke tests (#3397)

* remove babel and add configs

* add ts-node

* lint scripts

* eslint override

* remove type module

* add expect errors

* update js files to ts

* fix electron import

* remove errors

* update readme

* add build step

* typesync

* add eslintignore
This commit is contained in:
Opender Singh 2021-05-19 23:49:48 +12:00 committed by GitHub
parent a3a6c0fdfd
commit 5fa8f0069d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 255 additions and 56 deletions

View File

@ -1,15 +0,0 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "12"
}
}
]
],
"plugins": [
["@babel/plugin-proposal-optional-chaining"]
]
}

View File

@ -0,0 +1 @@
dist

View File

@ -0,0 +1,7 @@
/** @type { import('eslint').Linter.Config } */
module.exports = {
extends: '../../.eslintrc.js',
rules: {
'@typescript-eslint/no-use-before-define': 'off', // TSCONVERSION
},
};

View File

@ -32,11 +32,11 @@ npm run test:smoke:cli # Run CLI tests
npm run test:smoke:build # Run Insomnia tests
```
Sometimes, you might need to run tests against a _packaged_ application. A packaged application is the final artifact which bundles all of the various resources together, and is created for distribution in the form of a `.dmg` or `.exe`, etc. Packaging takes longer to do and is only required for edge cases (such as a [plugin installation](https://github.com/Kong/insomnia/blob/357b8f05f89fd5c07a75d8418670abe37b2882dc/packages/insomnia-smoke-test/designer/app.test.js#L36)), so we typically run tests against a build. To run packaged tests, from the root:
Sometimes, you might need to run tests against a _packaged_ application. A packaged application is the final artifact which bundles all of the various resources together, and is created for distribution in the form of a `.dmg` or `.exe`, etc. Packaging takes longer to do and is only required for edge cases (such as a <!-- TODO(TSCONVERSION) update this link -->[plugin installation](https://github.com/Kong/insomnia/blob/357b8f05f89fd5c07a75d8418670abe37b2882dc/packages/insomnia-smoke-test/designer/app.test.js#L36)), so we typically run tests against a build. To run packaged tests, from the root:
``` sh
npm run app-package:smoke # Package Insomnia
npm run test:smoke:package # Run Insomnia tests
npm run test:smoke:package # Run Insomnia tests
```
Each of the above commands will automatically run the Express server, so you do not need to take any extra steps.
@ -79,8 +79,8 @@ There are trade-offs with each selector approach but it's important to know how
#### Select by component and props
Sometimes selecting by a React component and props, directly from `app.client` is the cleanest approach, as the following two examples show:
```js
const waitUntilRequestIsActive = async (app, name) => {
```ts
const waitUntilRequestIsActive = async (app: Application, name: string) => {
const request = await app.client.react$('SidebarRequestRow', {
props: { isActive: true, request: { name } },
});
@ -103,8 +103,8 @@ It is important to scope an element to an appropriate ancestor. In a way the sel
In the following example, it is possible for multiple buttons which match the `button#enabled` selector to exist on the page. By chaining a React and CSS selector, we can ensure the test runner will always click the expected button within the `BasicAuth` component.
```js
export const toggleBasicAuthEnabled = async app => {
```ts
export const toggleBasicAuthEnabled = async (app: Application) => {
await app.client
.react$('BasicAuth')
.then(e => e.$('button#enabled'))
@ -116,8 +116,8 @@ A similar approach can be achieved through a CSS selector. In the following exam
These classes are fairly generic and could exist multiple times on the page, but the HTTP response code will always be in the response pane (`response-pane`) header (`pane__header`). As such, the selector is scoped to always select the expected element, wait for it to show, and ensure it has the expected text.
```js
export const expect200 = async app => {
```ts
export const expect200 = async (app: Application) => {
const tag = await app.client.$('.response-pane .pane__header .tag.bg-success');
await tag.waitForDisplayed();
await expectText(tag, '200 OK');
@ -130,8 +130,8 @@ As is common with all smoke testing frameworks, before interacting with an eleme
Sometimes you will need to add explicit pauses to allow for UI to refresh or database writes to occur (`await app.client.pause(500)`). Try to keep these to a minimum, though, exploring all other avenues first, such as WebdriverIO's `waitFor*` functions. Avoiding explicit waits ensures each test runs in the short amount of time.
When typing in the url bar for HTTP requests, we first wait for it to exist on the page before clicking on it and typing, because request activation can take some time.
```js
export const typeInUrlBar = async (app, url) => {
```ts
export const typeInUrlBar = async (app: Application, url: string) => {
const urlEditor = await app.client.react$('RequestUrlBar');
await urlEditor.waitForExist();
await urlEditor.click();
@ -140,7 +140,7 @@ export const typeInUrlBar = async (app, url) => {
```
In addition, sometimes we want to wait for an element to hide instead of show. To achieve this, we can use the `reverse` option available through WebdriverIO, as shown in the following example.
```js
```ts
// Wait for spinner to show
const spinner = await app.client.react$('ResponseTimer');
await spinner.waitForDisplayed();
@ -149,10 +149,10 @@ await spinner.waitForDisplayed();
await spinner.waitForDisplayed({ reverse: true });
```
### Readability
### Readability
It is important for a smoke test to be _readable_ so the flow can be understood, and the (often complicated) implementation details hidden, like in the example below.
```js
```ts
import * as debug from '../modules/debug';
it('sends request with basic authentication', async () => {
@ -197,11 +197,11 @@ Unlike unit tests, the application startup time for a smoke test can sometimes b
Smoke tests can potentially be flaky, and one attempt to avoid flaky tests in the default branch is to run the final implementation of a test atleast 20 times locally to prove its stability. If a test is unable to achieve this, it is very unlikely to be accepted into the test suite.
You can repeat a test quickly by wrapping it with the following block:
```js
```ts
describe.only.each(new Array(20).fill(1))('iteration %#', _ => {
it('your test name', () => {
//...
});
});
```
When raising a PR, paste a screenshot of the test results showing at least 20 successful iterations.
When raising a PR, paste a screenshot of the test results showing at least 20 successful iterations.

View File

@ -1,4 +1,7 @@
// @ts-expect-error TSMIGRATION
jasmine.getEnv().addReporter({
// @ts-expect-error TSMIGRATION
specStarted: result => (jasmine.currentTest = result),
// @ts-expect-error TSMIGRATION
specDone: result => (jasmine.currentTest = result),
});

View File

@ -5,6 +5,7 @@ describe('run test', () => {
it('can run unit test', () => {
const command = 'run test -a fixtures/inso-nedb TestSuite -e Dev';
// @ts-expect-error TSCONVERSION
const { failed } = execa.sync(getBinPathSync({ cwd: '../insomnia-inso' }), command.split(' '));
expect(failed).toBe(false);

View File

@ -8,10 +8,11 @@ import { basicAuthCreds } from '../fixtures/constants';
import * as onboarding from '../modules/onboarding';
import * as home from '../modules/home';
import * as modal from '../modules/modal';
import { Application } from 'spectron';
describe('Application launch', function() {
jest.setTimeout(50000);
let app = null;
let app: Application;
beforeEach(async () => {
app = await launchApp();

View File

@ -4,10 +4,11 @@ import * as onboarding from '../modules/onboarding';
import * as migration from '../modules/migration';
import * as home from '../modules/home';
import path from 'path';
import { Application } from 'spectron';
describe('Migration', function() {
jest.setTimeout(50000);
let app = null;
let app: Application;
beforeEach(async () => {
app = await launchApp(path.join(__dirname, '..', 'fixtures', 'basic-designer'));

View File

@ -5,13 +5,15 @@ import * as modal from '../modules/modal';
import * as dropdown from '../modules/dropdown';
import { isPackage, launchApp, stop } from '../modules/application';
import { Application } from 'spectron';
const itIf = condition => (condition ? it : it.skip);
// @ts-expect-error TSCONVERSION
it.if = itIf;
xdescribe('Application launch', function() {
jest.setTimeout(50000);
let app = null;
let app: Application;
beforeEach(async () => {
app = await launchApp();
@ -21,6 +23,7 @@ xdescribe('Application launch', function() {
await stop(app);
});
// @ts-expect-error TSCONVERSION
xit.if(isPackage())('can install and consume a plugin', async () => {
await client.correctlyLaunched(app);
await home.documentListingShown(app);

View File

@ -0,0 +1,7 @@
/** @type { import('@jest/types').Config.InitialOptions } */
module.exports = {
preset: '../../jest-preset.js',
setupFilesAfterEnv: [
'./__jest__/setup.ts',
],
};

View File

@ -1,6 +1,7 @@
import { Application } from 'spectron';
import path from 'path';
import os from 'os';
// @ts-expect-error TSCONVERSION
import electronPath from '../../insomnia-app/node_modules/electron';
import mkdirp from 'mkdirp';
import fs from 'fs';
@ -31,13 +32,14 @@ const spectronConfig = (
const env = { INSOMNIA_DATA_PATH: dataPath };
if (designerDataPath) {
// @ts-expect-error TSCONVERSION
env.DESIGNER_DATA_PATH = designerDataPath;
}
return { buildPath, packagePath, env };
};
export const launchApp = async designerDataPath => {
export const launchApp = async (designerDataPath?: string) => {
const config = spectronConfig(designerDataPath);
return await launch(config);
};
@ -93,7 +95,9 @@ export const stop = async app => {
};
const takeScreenshotOnFailure = async app => {
// @ts-expect-error TSCONVERSION
if (jasmine.currentTest.failedExpectations.length) {
// @ts-expect-error TSCONVERSION
await takeScreenshot(app, jasmine.currentTest.fullName.replace(/ /g, '_'));
}
};

View File

@ -1,5 +1,5 @@
import * as dropdown from '../modules/dropdown';
import * as modal from '../modules/modal';
import * as dropdown from './dropdown';
import * as modal from './modal';
import findAsync from './find-async';
import * as debug from './debug';
import faker from 'faker';

View File

@ -6,7 +6,7 @@ export const migrationMessageShown = async app => {
};
export const clickSkip = async app => {
const button = await app.client.react$('MigrationBody').then(e => e.$(`button=Skip for now`));
const button = await app.client.react$('MigrationBody').then(e => e.$('button=Skip for now'));
await button.waitForClickable();
await button.click();
};
@ -14,13 +14,13 @@ export const clickSkip = async app => {
export const toggleOption = async (app, label) => {
const toggle = await app.client
.$('.onboarding__content__body')
.then(e => e.react$(`BooleanSetting`, { props: { label } }));
.then(e => e.react$('BooleanSetting', { props: { label } }));
await toggle.waitForClickable();
await toggle.click();
};
const _getStartButton = async app => {
return await app.client.react$('MigrationBody').then(e => e.$(`button=Start Migration`));
return await app.client.react$('MigrationBody').then(e => e.$('button=Start Migration'));
};
export const clickStart = async app => {
@ -45,6 +45,6 @@ export const successMessageShown = async app => {
export const clickRestart = async app => {
await app.client
.react$('MigrationBody')
.then(e => e.$(`button=Restart Now`))
.then(e => e.$('button=Restart Now'))
.then(e => e.click());
};

View File

@ -1,6 +1,8 @@
import { Application } from 'spectron';
import findAsync from './find-async';
export const waitUntilOpened = async (app, { modalName, title }) => {
interface WaitUntilOpenedOptions {modalName?: string, title?: string}
export const waitUntilOpened = async (app, { modalName, title }: WaitUntilOpenedOptions) => {
if (modalName) {
const modal = await app.client.react$(modalName);
await modal.waitForDisplayed();
@ -9,7 +11,7 @@ export const waitUntilOpened = async (app, { modalName, title }) => {
}
};
export const close = async (app, modalName) => {
export const close = async (app: Application, modalName?: string) => {
let modal;
if (modalName) {
modal = await app.client.react$(modalName);

View File

@ -8,14 +8,14 @@ const analyticsMessageShown = async app => {
const clickDontShare = async app => {
await app.client
.$('.onboarding__content__body')
.then(e => e.$(`button=Don't share usage analytics`))
.then(e => e.$('button=Don\'t share usage analytics'))
.then(e => e.click());
};
const clickSkipImport = async app => {
await app.client
.$('.onboarding__content__body')
.then(e => e.$(`button=Skip`))
.then(e => e.$('button=Skip'))
.then(e => e.click());
};

View File

@ -997,6 +997,16 @@
"@babel/types": "^7.3.0"
}
},
"@types/body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
"dev": true,
"requires": {
"@types/connect": "*",
"@types/node": "*"
}
},
"@types/cacheable-request": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz",
@ -1015,6 +1025,53 @@
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
"dev": true
},
"@types/concurrently": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@types/concurrently/-/concurrently-6.0.1.tgz",
"integrity": "sha512-44I9tMSrgX7g39Ie7V/8N0OWG6696UtzPlv2ROsnQWyfyRVUp2Ue8ewxZkHopmX4Zyj6hiPgY1r14FqHsgfO4Q==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/connect": {
"version": "3.4.34",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz",
"integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/express": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz",
"integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==",
"dev": true,
"requires": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.18",
"@types/qs": "*",
"@types/serve-static": "*"
}
},
"@types/express-serve-static-core": {
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz",
"integrity": "sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA==",
"dev": true,
"requires": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*"
}
},
"@types/faker": {
"version": "5.5.5",
"resolved": "https://registry.npmjs.org/@types/faker/-/faker-5.5.5.tgz",
"integrity": "sha512-TNR5SjCg8sSfU4bdXsPJlpLXOH4YGBCVggvdZnttD2SMiONSxfJm231Nxn1VaQWWF2Twl4Wr2KC1hYaNd4M5Zw==",
"dev": true
},
"@types/graceful-fs": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
@ -1063,6 +1120,21 @@
"@types/node": "*"
}
},
"@types/mime": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
"dev": true
},
"@types/mkdirp": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.1.tgz",
"integrity": "sha512-HkGSK7CGAXncr8Qn/0VqNtExEE+PHMWb+qlR1faHMao7ng6P3tAaoWWBMdva0gL5h4zprjIO89GJOLXsMcDm1Q==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/node": {
"version": "14.0.27",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz",
@ -1090,6 +1162,18 @@
"@types/node": "*"
}
},
"@types/qs": {
"version": "6.9.6",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz",
"integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==",
"dev": true
},
"@types/range-parser": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
"dev": true
},
"@types/responselike": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
@ -1099,6 +1183,16 @@
"@types/node": "*"
}
},
"@types/serve-static": {
"version": "1.13.9",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz",
"integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==",
"dev": true,
"requires": {
"@types/mime": "^1",
"@types/node": "*"
}
},
"@types/stack-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz",
@ -1334,6 +1428,12 @@
}
}
},
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@ -2288,6 +2388,12 @@
"readable-stream": "^3.4.0"
}
},
"create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"cross-env": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz",
@ -2581,6 +2687,12 @@
"integrity": "sha512-9Uqnzy6m6zEStluH9iyJ3iHyaQziFnMnLeC8vK0eN6smiJmIx7+yB64d67C2lH/LZra+5cGscJAJsNXO+MdPMg==",
"dev": true
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"diff-sequences": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
@ -4689,6 +4801,12 @@
}
}
},
"make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"makeerror": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
@ -6665,6 +6783,20 @@
"utf8-byte-length": "^1.0.1"
}
},
"ts-node": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz",
"integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==",
"dev": true,
"requires": {
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.17",
"yn": "3.1.1"
}
},
"tslib": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
@ -7278,6 +7410,12 @@
"fd-slicer": "~1.1.0"
}
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
},
"zip-stream": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.0.2.tgz",

View File

@ -12,23 +12,27 @@
"url": "https://github.com/kong/insomnia/issues"
},
"version": "2.2.35",
"type": "module",
"scripts": {
"bootstrap": "npm run build",
"lint": "eslint . --ext .js,.ts,.tsx",
"lint:fix": "npm run lint -- --fix",
"clean": "tsc --build tsconfig.build.json --clean",
"postclean": "rimraf dist",
"build": "tsc --build tsconfig.build.json",
"spectron:build": "cross-env BUNDLE=build xvfb-maybe jest --detectOpenHandles --testPathPattern core",
"spectron:package": "cross-env BUNDLE=package xvfb-maybe jest --detectOpenHandles --testPathPattern core",
"cli": "jest --detectOpenHandles --testPathPattern cli",
"serve": "node server/index.js",
"serve": "ts-node server/index.ts",
"with-mock": "concurrently --names server,app --success first --kill-others \"npm run serve\"",
"test:cli": "npm run with-mock \"npm run cli\"",
"test:build": "npm run with-mock \"npm run spectron:build\"",
"test:package": "npm run with-mock \"npm run spectron:package\""
},
"jest": {
"setupFilesAfterEnv": [
"./__jest__/setup.js"
]
},
"devDependencies": {
"@types/concurrently": "^6.0.1",
"@types/express": "^4.17.11",
"@types/faker": "^5.5.5",
"@types/mkdirp": "^1.0.1",
"concurrently": "^5.3.0",
"cross-env": "^7.0.2",
"execa": "^5.0.0",
@ -40,6 +44,7 @@
"mkdirp": "^1.0.4",
"spectron": "^11.1.0",
"spectron-keys": "0.0.1",
"ts-node": "^9.1.1",
"xvfb-maybe": "^0.2.1"
}
}

View File

@ -1,13 +1,13 @@
import express from 'express';
import basicAuth from 'express-basic-auth';
import { basicAuthCreds } from '../fixtures/constants.js';
import { basicAuthCreds } from '../fixtures/constants';
const app = express();
const basicAuthRouter = express.Router();
const port = 4010;
// Artificially slow each request down
app.use((req, res, next) => {
app.use((_req, _res, next) => {
setTimeout(next, 500);
});
@ -40,8 +40,8 @@ app.listen(port, () => {
});
app.get('/delay/seconds/:duration', (req, res) => {
const delaySec = Number.parseInt(req.params.duration || 2);
setTimeout(function () {
const delaySec = Number.parseInt(req.params.duration || '2');
setTimeout(function() {
res.send(`Delayed by ${delaySec} seconds`);
}, delaySec * 1000);
})
});

View File

@ -0,0 +1,23 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"outDir": "dist",
"rootDir": ".",
"resolveJsonModule": true,
"esModuleInterop": true,
"skipLibCheck": true, // this is required because spectron depends on electron but it is not locatable by typescript for the purpose of types
"noImplicitAny": false
},
"include": [
"cli",
"core",
"designer",
"fixtures",
"modules",
"server"
],
"exclude": [
"dist"
]
}

View File

@ -0,0 +1,18 @@
{
"extends": "./tsconfig.build.json",
"compilerOptions": {
"composite": false,
"rootDir": "."
},
"include": [
"__jest__",
"cli",
"core",
"designer",
"fixtures",
"modules",
"server",
"jest.config.js",
".eslintrc.js"
]
}