diff --git a/packages/insomnia-smoke-test/.babelrc b/packages/insomnia-smoke-test/.babelrc deleted file mode 100644 index 09fb920a119..00000000000 --- a/packages/insomnia-smoke-test/.babelrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "node": "12" - } - } - ] - ], - "plugins": [ - ["@babel/plugin-proposal-optional-chaining"] - ] -} diff --git a/packages/insomnia-smoke-test/README.md b/packages/insomnia-smoke-test/README.md index 77a1f8a6402..4673840f6e9 100644 --- a/packages/insomnia-smoke-test/README.md +++ b/packages/insomnia-smoke-test/README.md @@ -32,7 +32,7 @@ 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 [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 @@ -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: App, name: string) => { const request = await app.client.react$('SidebarRequestRow', { props: { isActive: true, request: { name } }, }); @@ -88,7 +88,7 @@ const waitUntilRequestIsActive = async (app, name) => { await request.waitForDisplayed(); }; -export const clickFolderByName = async (app, name) => { +export const clickFolderByName = async (app: App, name: string) => { const folder = await app.client.react$('SidebarRequestGroupRow', { props: { requestGroup: { 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: App) => { 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: App) => { const tag = await app.client.$('.response-pane .pane__header .tag.bg-success'); await tag.waitForDisplayed(); await expectText(tag, '200 OK'); @@ -130,8 +130,9 @@ 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: App, url: string) => { const urlEditor = await app.client.react$('RequestUrlBar'); await urlEditor.waitForExist(); await urlEditor.click(); @@ -140,7 +141,8 @@ 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(); @@ -152,7 +154,7 @@ await spinner.waitForDisplayed({ reverse: true }); ### 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 +199,13 @@ 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. \ No newline at end of file diff --git a/packages/insomnia-smoke-test/jest.config.js b/packages/insomnia-smoke-test/jest.config.js new file mode 100644 index 00000000000..baae67b2818 --- /dev/null +++ b/packages/insomnia-smoke-test/jest.config.js @@ -0,0 +1,18 @@ +/** @type { import('@jest/types').Config.InitialOptions } */ +module.exports = { + globals: { + 'ts-jest': { + isolatedModules: true, + }, + }, + setupFilesAfterEnv: ['./jest/setup.ts'], + testEnvironment: 'node', + transform: { + '^.+\\.tsx?$': 'ts-jest', + }, + testRegex: ['.+\\.test\\.ts$'], + collectCoverage: false, + collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], + coverageReporters: ['text-summary', 'lcov'], +}; diff --git a/packages/insomnia-smoke-test/modules/find-async.js b/packages/insomnia-smoke-test/modules/find-async.js deleted file mode 100644 index 2e2e797c0a1..00000000000 --- a/packages/insomnia-smoke-test/modules/find-async.js +++ /dev/null @@ -1,6 +0,0 @@ -export default async function findAsync(arr, asyncCallback) { - const promises = arr.map(asyncCallback); - const results = await Promise.all(promises); - const index = results.findIndex(result => result); - return arr[index]; -} diff --git a/packages/insomnia-smoke-test/modules/tabs.js b/packages/insomnia-smoke-test/modules/tabs.js deleted file mode 100644 index cc1f5f740f3..00000000000 --- a/packages/insomnia-smoke-test/modules/tabs.js +++ /dev/null @@ -1,3 +0,0 @@ -export const clickTabByText = async (element, text) => { - await element.$(`.react-tabs__tab=${text}`).then(e => e.click()); -}; diff --git a/packages/insomnia-smoke-test/package-lock.json b/packages/insomnia-smoke-test/package-lock.json index 7e638b876d7..dbe031ee367 100644 --- a/packages/insomnia-smoke-test/package-lock.json +++ b/packages/insomnia-smoke-test/package-lock.json @@ -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", diff --git a/packages/insomnia-smoke-test/package.json b/packages/insomnia-smoke-test/package.json index 4af4dae21a5..312373a9ab7 100644 --- a/packages/insomnia-smoke-test/package.json +++ b/packages/insomnia-smoke-test/package.json @@ -14,21 +14,27 @@ "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", + "test": "jest --silent", "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 src/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 +46,7 @@ "mkdirp": "^1.0.4", "spectron": "^11.1.0", "spectron-keys": "0.0.1", + "ts-node": "^9.1.1", "xvfb-maybe": "^0.2.1" } } diff --git a/packages/insomnia-smoke-test/cli/app.test.js b/packages/insomnia-smoke-test/src/cli/app.test.ts similarity index 83% rename from packages/insomnia-smoke-test/cli/app.test.js rename to packages/insomnia-smoke-test/src/cli/app.test.ts index 12e4da6374d..e683ff6cad6 100644 --- a/packages/insomnia-smoke-test/cli/app.test.js +++ b/packages/insomnia-smoke-test/src/cli/app.test.ts @@ -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 appears to be a genuine error const { failed } = execa.sync(getBinPathSync({ cwd: '../insomnia-inso' }), command.split(' ')); expect(failed).toBe(false); diff --git a/packages/insomnia-smoke-test/core/app.test.js b/packages/insomnia-smoke-test/src/core/app.test.ts similarity index 94% rename from packages/insomnia-smoke-test/core/app.test.js rename to packages/insomnia-smoke-test/src/core/app.test.ts index 9a3ab68743e..06ac37579f4 100644 --- a/packages/insomnia-smoke-test/core/app.test.js +++ b/packages/insomnia-smoke-test/src/core/app.test.ts @@ -8,10 +8,12 @@ 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; + // @ts-expect-error -- TSCONVERSION need to do the null check or find some other mechanism for non null here + let app: Application = null; beforeEach(async () => { app = await launchApp(); @@ -138,8 +140,10 @@ describe('Application launch', function() { // Click the "Deploy to Portal" button, installed from that plugin await dropdown.clickOpenDropdownItemByText(app, 'Deploy to Portal'); + // @ts-expect-error -- TSCONVERSION appears to be genuine // Ensure a modal opens, then close it - the rest is plugin behavior await modal.waitUntilOpened(app, { title: 'Deploy to Portal' }); + // @ts-expect-error -- TSCONVERSION appears to be genuine await modal.close(app); }); @@ -160,6 +164,7 @@ describe('Application launch', function() { // Import from clipboard as collection await home.importFromClipboard(app); + // @ts-expect-error -- TSCONVERSION appears to be genuine await modal.waitUntilOpened(app, { title: 'Import As' }); await modal.clickModalFooterByText(app, 'Request Collection'); await home.expectTotalDocuments(app, 2); @@ -171,12 +176,14 @@ describe('Application launch', function() { // Delete the collection await home.openDocumentMenuDropdown(collCard); await dropdown.clickDropdownItemByText(collCard, 'Delete'); + // @ts-expect-error -- TSCONVERSION appears to be genuine await modal.waitUntilOpened(app, { title: 'Delete Collection' }); await modal.clickModalFooterByText(app, 'Yes'); await home.expectTotalDocuments(app, 1); // Import from clipboard as document await home.importFromClipboard(app); + // @ts-expect-error -- TSCONVERSION appears to be genuine await modal.waitUntilOpened(app, { title: 'Import As' }); await modal.clickModalFooterByText(app, 'Design Document'); await home.expectTotalDocuments(app, 2); diff --git a/packages/insomnia-smoke-test/core/migration.test.js b/packages/insomnia-smoke-test/src/core/migration.test.ts similarity index 94% rename from packages/insomnia-smoke-test/core/migration.test.js rename to packages/insomnia-smoke-test/src/core/migration.test.ts index 43531e7b3c6..c64d68cb2a4 100644 --- a/packages/insomnia-smoke-test/core/migration.test.js +++ b/packages/insomnia-smoke-test/src/core/migration.test.ts @@ -4,10 +4,12 @@ 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; + // @ts-expect-error -- TSCONVERSION + let app: Application = null; beforeEach(async () => { app = await launchApp(path.join(__dirname, '..', 'fixtures', 'basic-designer')); diff --git a/packages/insomnia-smoke-test/designer/app.test.js b/packages/insomnia-smoke-test/src/designer/app.test.ts similarity index 75% rename from packages/insomnia-smoke-test/designer/app.test.js rename to packages/insomnia-smoke-test/src/designer/app.test.ts index bfac1e4cf04..9f1692bc347 100644 --- a/packages/insomnia-smoke-test/designer/app.test.js +++ b/packages/insomnia-smoke-test/src/designer/app.test.ts @@ -5,13 +5,16 @@ 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); +const itIf = (condition: boolean) => (condition ? it : it.skip); +// @ts-expect-error -- TSCONVERSION need to augment jest it.if = itIf; xdescribe('Application launch', function() { jest.setTimeout(50000); - let app = null; + // @ts-expect-error -- TSCONVERSION + let app: Application = null; beforeEach(async () => { app = await launchApp(); @@ -21,6 +24,7 @@ xdescribe('Application launch', function() { await stop(app); }); + // @ts-expect-error -- TSCONVERSION need to augment jest xit.if(isPackage())('can install and consume a plugin', async () => { await client.correctlyLaunched(app); await home.documentListingShown(app); @@ -38,7 +42,9 @@ xdescribe('Application launch', function() { await dropdown.clickDropdownItemByText(dd, 'Deploy to Portal'); // Ensure a modal opens, then close it - the rest is plugin behavior + // @ts-expect-error -- TSCONVERSION appears to be genuine await modal.waitUntilOpened(app, { title: 'Deploy to Portal' }); + // @ts-expect-error -- TSCONVERSION appears to be genuine await modal.close(app); }); }); diff --git a/packages/insomnia-smoke-test/src/entities.ts b/packages/insomnia-smoke-test/src/entities.ts new file mode 100644 index 00000000000..5f3b1f59716 --- /dev/null +++ b/packages/insomnia-smoke-test/src/entities.ts @@ -0,0 +1,7 @@ +import { AppConstructorOptions } from 'spectron'; + +export interface Config { + packagePath: string; + buildPath: string; + env?: AppConstructorOptions['env']; +} diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.ApiSpec.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.ApiSpec.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.ApiSpec.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.ApiSpec.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.ClientCertificate.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.ClientCertificate.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.ClientCertificate.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.ClientCertificate.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.CookieJar.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.CookieJar.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.CookieJar.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.CookieJar.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Environment.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Environment.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Environment.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Environment.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.GitRepository.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.GitRepository.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.GitRepository.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.GitRepository.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.GrpcRequest.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.GrpcRequest.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.GrpcRequest.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.GrpcRequest.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.GrpcRequestMeta.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.GrpcRequestMeta.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.GrpcRequestMeta.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.GrpcRequestMeta.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.OAuth2Token.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.OAuth2Token.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.OAuth2Token.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.OAuth2Token.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.PluginData.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.PluginData.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.PluginData.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.PluginData.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.ProtoDirectory.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.ProtoDirectory.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.ProtoDirectory.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.ProtoDirectory.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.ProtoFile.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.ProtoFile.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.ProtoFile.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.ProtoFile.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Request.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Request.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Request.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Request.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.RequestGroup.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.RequestGroup.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.RequestGroup.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.RequestGroup.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.RequestGroupMeta.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.RequestGroupMeta.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.RequestGroupMeta.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.RequestGroupMeta.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.RequestMeta.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.RequestMeta.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.RequestMeta.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.RequestMeta.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.RequestVersion.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.RequestVersion.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.RequestVersion.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.RequestVersion.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Response.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Response.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Response.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Response.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Settings.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Settings.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Settings.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Settings.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Stats.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Stats.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Stats.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Stats.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.UnitTest.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.UnitTest.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.UnitTest.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.UnitTest.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.UnitTestResult.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.UnitTestResult.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.UnitTestResult.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.UnitTestResult.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.UnitTestSuite.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.UnitTestSuite.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.UnitTestSuite.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.UnitTestSuite.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Workspace.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Workspace.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.Workspace.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.Workspace.db diff --git a/packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.WorkspaceMeta.db b/packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.WorkspaceMeta.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/basic-designer/insomnia.WorkspaceMeta.db rename to packages/insomnia-smoke-test/src/fixtures/basic-designer/insomnia.WorkspaceMeta.db diff --git a/packages/insomnia-smoke-test/fixtures/constants.js b/packages/insomnia-smoke-test/src/fixtures/constants.ts similarity index 81% rename from packages/insomnia-smoke-test/fixtures/constants.js rename to packages/insomnia-smoke-test/src/fixtures/constants.ts index ba378a62b1e..645c0168d83 100644 --- a/packages/insomnia-smoke-test/fixtures/constants.js +++ b/packages/insomnia-smoke-test/src/fixtures/constants.ts @@ -1,4 +1,4 @@ -const getCreds = (user, pass, encoding) => ({ +const getCreds = (user: string, pass: string, encoding: BufferEncoding) => ({ raw: { user, pass }, encoded: { user: Buffer.from(user, encoding).toString(), diff --git a/packages/insomnia-smoke-test/fixtures/dummy.csv b/packages/insomnia-smoke-test/src/fixtures/dummy.csv similarity index 100% rename from packages/insomnia-smoke-test/fixtures/dummy.csv rename to packages/insomnia-smoke-test/src/fixtures/dummy.csv diff --git a/packages/insomnia-smoke-test/fixtures/dummy.pdf b/packages/insomnia-smoke-test/src/fixtures/dummy.pdf similarity index 100% rename from packages/insomnia-smoke-test/fixtures/dummy.pdf rename to packages/insomnia-smoke-test/src/fixtures/dummy.pdf diff --git a/packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.ApiSpec.db b/packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.ApiSpec.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.ApiSpec.db rename to packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.ApiSpec.db diff --git a/packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.Environment.db b/packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.Environment.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.Environment.db rename to packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.Environment.db diff --git a/packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.Request.db b/packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.Request.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.Request.db rename to packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.Request.db diff --git a/packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.RequestGroup.db b/packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.RequestGroup.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.RequestGroup.db rename to packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.RequestGroup.db diff --git a/packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.UnitTest.db b/packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.UnitTest.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.UnitTest.db rename to packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.UnitTest.db diff --git a/packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.UnitTestSuite.db b/packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.UnitTestSuite.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.UnitTestSuite.db rename to packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.UnitTestSuite.db diff --git a/packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.Workspace.db b/packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.Workspace.db similarity index 100% rename from packages/insomnia-smoke-test/fixtures/inso-nedb/insomnia.Workspace.db rename to packages/insomnia-smoke-test/src/fixtures/inso-nedb/insomnia.Workspace.db diff --git a/packages/insomnia-smoke-test/fixtures/swagger2.yaml b/packages/insomnia-smoke-test/src/fixtures/swagger2.yaml similarity index 100% rename from packages/insomnia-smoke-test/fixtures/swagger2.yaml rename to packages/insomnia-smoke-test/src/fixtures/swagger2.yaml diff --git a/packages/insomnia-smoke-test/__jest__/setup.js b/packages/insomnia-smoke-test/src/jest/setup.ts similarity index 56% rename from packages/insomnia-smoke-test/__jest__/setup.js rename to packages/insomnia-smoke-test/src/jest/setup.ts index 3da8848723c..7fde1f7de7b 100644 --- a/packages/insomnia-smoke-test/__jest__/setup.js +++ b/packages/insomnia-smoke-test/src/jest/setup.ts @@ -1,4 +1,8 @@ + +// @ts-expect-error -- TSCONVERSION jasmine.getEnv().addReporter({ + // @ts-expect-error -- TSCONVERSION specStarted: result => (jasmine.currentTest = result), + // @ts-expect-error -- TSCONVERSION specDone: result => (jasmine.currentTest = result), }); diff --git a/packages/insomnia-smoke-test/modules/application.js b/packages/insomnia-smoke-test/src/modules/application.ts similarity index 70% rename from packages/insomnia-smoke-test/modules/application.js rename to packages/insomnia-smoke-test/src/modules/application.ts index 6ac57b93d16..109fa316e89 100644 --- a/packages/insomnia-smoke-test/modules/application.js +++ b/packages/insomnia-smoke-test/src/modules/application.ts @@ -1,9 +1,11 @@ import { Application } from 'spectron'; import path from 'path'; import os from 'os'; -import electronPath from '../../insomnia-app/node_modules/electron'; import mkdirp from 'mkdirp'; import fs from 'fs'; +import { Config } from '../entities'; + +const electronPath = '../../../insomnia-app/node_modules/electron'; const getAppPlatform = () => process.platform; const isMac = () => getAppPlatform() === 'darwin'; @@ -14,7 +16,7 @@ export const isBuild = () => process.env.BUNDLE === 'build'; export const isPackage = () => process.env.BUNDLE === 'package'; const spectronConfig = ( - designerDataPath = path.join(__dirname, '..', 'fixtures', 'doesnt-exist'), + designerDataPath = path.join(__dirname, '..', '..', 'fixtures', 'doesnt-exist'), ) => { let packagePathSuffix = ''; if (isWindows()) { @@ -25,24 +27,23 @@ const spectronConfig = ( packagePathSuffix = ''; // TODO: find out what this is } - const buildPath = path.join(__dirname, '../../insomnia-app/build'); - const packagePath = path.join(__dirname, '../../insomnia-app/dist', packagePathSuffix); + const buildPath = path.join(__dirname, '../../../insomnia-app/build'); + const packagePath = path.join(__dirname, '../../../insomnia-app/dist', packagePathSuffix); const dataPath = path.join(os.tmpdir(), 'insomnia-smoke-test', `${Date.now()}`); - const env = { INSOMNIA_DATA_PATH: dataPath }; + const env: { + DESIGNER_DATA_PATH?: string; + INSOMNIA_DATA_PATH: string; + } = { INSOMNIA_DATA_PATH: dataPath }; if (designerDataPath) { env.DESIGNER_DATA_PATH = designerDataPath; } - return { buildPath, packagePath, env }; -}; - -export const launchApp = async designerDataPath => { - const config = spectronConfig(designerDataPath); - return await launch(config); + const config: Config = { buildPath, packagePath, env }; + return config; }; -const getLaunchPath = config => +const getLaunchPath = (config: Config) => isPackage() ? { path: config.packagePath } : { @@ -50,7 +51,7 @@ const getLaunchPath = config => args: [config.buildPath], }; -const launch = async config => { +const launch = async (config?: Config) => { if (!config) { throw new Error('Spectron config could not be loaded.'); } @@ -69,7 +70,9 @@ const launch = async config => { // Windows spawns two terminal windows when running spectron, and the only workaround // is to focus the window on start. // https://github.com/electron-userland/spectron/issues/60 + // @ts-expect-error -- TSCONVERSION await app.browserWindow.focus(); + // @ts-expect-error -- TSCONVERSION await app.browserWindow.setAlwaysOnTop(true); // Set the implicit wait timeout to 0 (webdriver default) @@ -79,27 +82,35 @@ const launch = async config => { await app.client.setTimeout({ implicit: 0 }); // Set bounds to default size + // @ts-expect-error -- TSCONVERSION await app.browserWindow.setSize(1280, 700); }); return app; }; -export const stop = async app => { - await takeScreenshotOnFailure(app); +export const launchApp = async (designerDataPath?: string) => { + const config = spectronConfig(designerDataPath); + return await launch(config); +}; - if (app && app.isRunning()) { - await app.stop(); - } +export const takeScreenshot = async (app: Application, name: string) => { + mkdirp.sync('screenshots'); + const buffer = await app.browserWindow.capturePage(); + await fs.promises.writeFile(path.join('screenshots', `${name}.png`), buffer); }; -const takeScreenshotOnFailure = async app => { +const takeScreenshotOnFailure = async (app: Application) => { + // @ts-expect-error -- TSCONVERSION if (jasmine.currentTest.failedExpectations.length) { + // @ts-expect-error -- TSCONVERSION await takeScreenshot(app, jasmine.currentTest.fullName.replace(/ /g, '_')); } }; -export const takeScreenshot = async (app, name) => { - mkdirp.sync('screenshots'); - const buffer = await app.browserWindow.capturePage(); - await fs.promises.writeFile(path.join('screenshots', `${name}.png`), buffer); +export const stop = async (app: Application) => { + await takeScreenshotOnFailure(app); + + if (app?.isRunning()) { + await app.stop(); + } }; diff --git a/packages/insomnia-smoke-test/modules/client.js b/packages/insomnia-smoke-test/src/modules/client.ts similarity index 60% rename from packages/insomnia-smoke-test/modules/client.js rename to packages/insomnia-smoke-test/src/modules/client.ts index c9b60bd7a2d..879a5c68445 100644 --- a/packages/insomnia-smoke-test/modules/client.js +++ b/packages/insomnia-smoke-test/src/modules/client.ts @@ -1,11 +1,16 @@ -export const correctlyLaunched = async app => { +import { Application } from 'spectron'; + +export const correctlyLaunched = async (app: Application) => { + // @ts-expect-error -- TSCONVERSION appears to be genuine await expect(app.browserWindow.isDevToolsOpened()).resolves.toBe(false); await expect(app.client.getWindowCount()).resolves.toBe(1); + // @ts-expect-error -- TSCONVERSION await expect(app.browserWindow.isMinimized()).resolves.toBe(false); + // @ts-expect-error -- TSCONVERSION await expect(app.browserWindow.isFocused()).resolves.toBe(true); }; -export const focusAfterRestart = async app => { +export const focusAfterRestart = async (app: Application) => { await app.client.pause(4000); const count = await app.client.getWindowCount(); diff --git a/packages/insomnia-smoke-test/modules/debug.js b/packages/insomnia-smoke-test/src/modules/debug.ts similarity index 69% rename from packages/insomnia-smoke-test/modules/debug.js rename to packages/insomnia-smoke-test/src/modules/debug.ts index aa355561e52..02a3cc1d167 100644 --- a/packages/insomnia-smoke-test/modules/debug.js +++ b/packages/insomnia-smoke-test/src/modules/debug.ts @@ -1,25 +1,53 @@ import faker from 'faker'; -import spectronKeys from 'spectron-keys'; +import { Application } from 'spectron'; +import { mapAccelerator } from 'spectron-keys'; -export const workspaceDropdownExists = async (app, workspaceName = 'Insomnia') => { +// @ts-expect-error -- TSCONVERSION +export const expectText = async (element, text: string) => { + await expect(element.getText()).resolves.toBe(text); +}; + +// @ts-expect-error -- TSCONVERSION +export const expectContainsText = async (element, text: string) => { + await expect(element.getText()).resolves.toContain(text); +}; + +// @ts-expect-error -- TSCONVERSION +export const expectNotContainsText = async (element, text: string) => { + await expect(element.getText()).resolves.not.toContain(text); +}; + +export const selectAll = async (app: Application) => { + await app.client.keys(mapAccelerator('CommandOrControl+A')); +}; + +export const workspaceDropdownExists = async (app: Application, workspaceName = 'Insomnia') => { await app.client.waitUntilTextExists('.workspace-dropdown', workspaceName); }; -export const pageDisplayed = async app => { +export const pageDisplayed = async (app: Application) => { await app.client.react$('WrapperDebug').then(e => e.waitForDisplayed()); }; -export const clickWorkspaceDropdown = async app => { +export const clickWorkspaceDropdown = async (app: Application) => { const dropdown = await app.client.react$('WorkspaceDropdown'); await dropdown.click(); return dropdown; }; -export const goToDashboard = async app => { +export const goToDashboard = async (app: Application) => { await app.client.$('.header_left a').then(e => e.click()); }; -export const createNewRequest = async (app, name) => { +const waitUntilRequestIsActive = async (app: Application, name: string) => { + const request = await app.client.react$('SidebarRequestRow', { + props: { isActive: true, request: { name } }, + }); + + await request.waitForDisplayed(); +}; + +export const createNewRequest = async (app: Application, name: string) => { await app.client.$('.sidebar .dropdown .fa-plus-circle').then(e => e.click()); await app.client @@ -35,6 +63,7 @@ export const createNewRequest = async (app, name) => { const requestName = `${name}-${faker.lorem.slug()}`; await input.waitUntil(() => input.isFocused()); + // @ts-expect-error -- TSCONVERSION appears to be genuine await input.keys(requestName); await app.client @@ -45,15 +74,7 @@ export const createNewRequest = async (app, name) => { await waitUntilRequestIsActive(app, requestName); }; -const waitUntilRequestIsActive = async (app, name) => { - const request = await app.client.react$('SidebarRequestRow', { - props: { isActive: true, request: { name } }, - }); - - await request.waitForDisplayed(); -}; - -export const clickFolderByName = async (app, name) => { +export const clickFolderByName = async (app: Application, name: string) => { const folder = await app.client.react$('SidebarRequestGroupRow', { props: { requestGroup: { name } }, }); @@ -62,7 +83,7 @@ export const clickFolderByName = async (app, name) => { await folder.click(); }; -export const clickRequestByName = async (app, name) => { +export const clickRequestByName = async (app: Application, name: string) => { const folder = await app.client.react$('SidebarRequestRow', { props: { request: { name } }, }); @@ -71,14 +92,15 @@ export const clickRequestByName = async (app, name) => { await folder.click(); }; -export const typeInUrlBar = async (app, url) => { +export const typeInUrlBar = async (app: Application, url: string) => { const urlEditor = await app.client.react$('RequestUrlBar'); await urlEditor.waitForExist(); await urlEditor.click(); + // @ts-expect-error -- TSCONVERSION appears to be genuine await urlEditor.keys(url); }; -export const clickSendRequest = async app => { +export const clickSendRequest = async (app: Application) => { await app.client .react$('RequestUrlBar') .then(e => e.$('.urlbar__send-btn')) @@ -92,38 +114,38 @@ export const clickSendRequest = async app => { await spinner.waitForDisplayed({ reverse: true }); }; -export const expect200 = async app => { +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'); }; -export const expect401 = async app => { +export const expect401 = async (app: Application) => { const tag = await app.client.$('.response-pane .pane__header .tag.bg-warning'); await tag.waitForDisplayed(); await expectText(tag, '401 Unauthorized'); }; -export const getResponseViewer = async app => { +export const getResponseViewer = async (app: Application) => { // app.client.react$('ResponseViewer') doesn't seem to work because ResponseViewer is not a PureComponent const codeEditor = await app.client.$('.response-pane .editor'); await codeEditor.waitForDisplayed(); return codeEditor; }; -export const getTimelineViewer = async app => { +export const getTimelineViewer = async (app: Application) => { const codeEditor = await app.client.react$('ResponseTimelineViewer'); await codeEditor.waitForDisplayed(); return codeEditor; }; -export const getCsvViewer = async app => { +export const getCsvViewer = async (app: Application) => { const csvViewer = await app.client.react$('ResponseCSVViewer'); await csvViewer.waitForDisplayed(); return csvViewer; }; -export const getPdfCanvas = async app => { +export const getPdfCanvas = async (app: Application) => { const pdfViewer = await app.client.react$('ResponsePDFViewer'); await pdfViewer.waitForDisplayed(); const canvas = await pdfViewer.$('.S-PDF-ID canvas'); @@ -131,14 +153,14 @@ export const getPdfCanvas = async app => { return canvas; }; -export const clickRequestAuthDropdown = async app => { +export const clickRequestAuthDropdown = async (app: Application) => { await app.client .react$('AuthDropdown') .then(e => e.react$('DropdownButton')) .then(e => e.click()); }; -export const clickRequestAuthTab = async app => { +export const clickRequestAuthTab = async (app: Application) => { await app.client .react$('RequestPane') .then(e => e.$('#react-tabs-2')) @@ -147,7 +169,7 @@ export const clickRequestAuthTab = async app => { const basicAuthPause = 300; -export const clickBasicAuth = async app => { +export const clickBasicAuth = async (app: Application) => { await app.client .react$('AuthDropdown') .then(e => e.react$('DropdownItem', { props: { value: 'basic' } })) @@ -157,13 +179,18 @@ export const clickBasicAuth = async app => { await app.client.pause(basicAuthPause); }; -export const expectNoAuthSelected = async app => { +export const expectNoAuthSelected = async (app: Application) => { const wrapper = await app.client.react$('RequestPane').then(e => e.react$('AuthWrapper')); await wrapper.waitForDisplayed(); await expectText(wrapper, 'Select an auth type from above'); }; -export const typeBasicAuthUsernameAndPassword = async (app, username, password, clear = false) => { +export const typeBasicAuthUsernameAndPassword = async ( + app: Application, + username: string, + password: string, + clear = false, +) => { const basicAuth = await app.client.react$('BasicAuth'); await basicAuth.waitForExist(); @@ -179,6 +206,7 @@ export const typeBasicAuthUsernameAndPassword = async (app, username, password, if (clear) { await selectAll(app); } + // @ts-expect-error -- TSCONVERSION appears to be genuine await usernameEditor.keys(username); const passwordEditor = await app.client.react$('OneLineEditor', { @@ -194,13 +222,14 @@ export const typeBasicAuthUsernameAndPassword = async (app, username, password, if (clear) { await selectAll(app); } + // @ts-expect-error -- TSCONVERSION appears to be genuine await passwordEditor.keys(password); // Allow password changes to persist await app.client.pause(basicAuthPause); }; -export const toggleBasicAuthEnabled = async app => { +export const toggleBasicAuthEnabled = async (app: Application) => { await app.client .react$('BasicAuth') .then(e => e.$('button#enabled')) @@ -209,7 +238,7 @@ export const toggleBasicAuthEnabled = async app => { await app.client.pause(basicAuthPause); }; -export const toggleBasicAuthEncoding = async app => { +export const toggleBasicAuthEncoding = async (app: Application) => { await app.client .react$('BasicAuth') .then(e => e.$('button#use-iso-8859-1')) @@ -219,19 +248,7 @@ export const toggleBasicAuthEncoding = async app => { await app.client.pause(basicAuthPause); }; -export const expectText = async (element, text) => { - await expect(element.getText()).resolves.toBe(text); -}; - -export const expectContainsText = async (element, text) => { - await expect(element.getText()).resolves.toContain(text); -}; - -export const expectNotContainsText = async (element, text) => { - await expect(element.getText()).resolves.not.toContain(text); -}; - -export const clickTimelineTab = async app => { +export const clickTimelineTab = async (app: Application) => { await app.client .$('.response-pane') .then(e => e.$('#react-tabs-16')) @@ -239,9 +256,6 @@ export const clickTimelineTab = async app => { // Wait until some text shows const codeEditor = await getTimelineViewer(app); + // @ts-expect-error -- TSCONVERSION appears to be genuine await app.client.waitUntil(() => codeEditor.getText()); }; - -export const selectAll = async app => { - await app.client.keys(spectronKeys.mapAccelerator('CommandOrControl+A')); -}; diff --git a/packages/insomnia-smoke-test/modules/dropdown.js b/packages/insomnia-smoke-test/src/modules/dropdown.ts similarity index 67% rename from packages/insomnia-smoke-test/modules/dropdown.js rename to packages/insomnia-smoke-test/src/modules/dropdown.ts index 8025636c131..d9355dca68b 100644 --- a/packages/insomnia-smoke-test/modules/dropdown.js +++ b/packages/insomnia-smoke-test/src/modules/dropdown.ts @@ -1,5 +1,7 @@ -import findAsync from './find-async'; +import { Application } from 'spectron'; +import { findAsync } from './find-async'; +// @ts-expect-error -- TSCONVERSION const findDropdownItemWithText = async (parent, text) => { let item; await parent.waitUntil(async () => { @@ -10,13 +12,16 @@ const findDropdownItemWithText = async (parent, text) => { return item; }; +// @ts-expect-error -- TSCONVERSION export const clickDropdownItemByText = async (parent, text) => { const item = await findDropdownItemWithText(parent, text); + // @ts-expect-error -- TSCONVERSION await item.waitForDisplayed(); + // @ts-expect-error -- TSCONVERSION await item.click(); }; -export const clickOpenDropdownItemByText = async (app, text) => { +export const clickOpenDropdownItemByText = async (app: Application, text: string) => { const item = await app.client .$('.dropdown__menu[aria-hidden=false]') .then(e => e.$(`button*=${text}`)); diff --git a/packages/insomnia-smoke-test/src/modules/find-async.ts b/packages/insomnia-smoke-test/src/modules/find-async.ts new file mode 100644 index 00000000000..e51655976a4 --- /dev/null +++ b/packages/insomnia-smoke-test/src/modules/find-async.ts @@ -0,0 +1,9 @@ +export async function findAsync( + arr: Input[], + asyncCallback: (value: Input, index: number, array: Input[]) => Promise, +) { + const promises = arr.map>(asyncCallback); + const results = await Promise.all(promises); + const index = results.findIndex(result => result); + return arr[index]; +} diff --git a/packages/insomnia-smoke-test/modules/home.js b/packages/insomnia-smoke-test/src/modules/home.ts similarity index 63% rename from packages/insomnia-smoke-test/modules/home.js rename to packages/insomnia-smoke-test/src/modules/home.ts index 791e0cc9f69..e7d26d769b1 100644 --- a/packages/insomnia-smoke-test/modules/home.js +++ b/packages/insomnia-smoke-test/src/modules/home.ts @@ -1,19 +1,20 @@ -import * as dropdown from '../modules/dropdown'; -import * as modal from '../modules/modal'; -import findAsync from './find-async'; +import * as dropdown from './dropdown'; +import * as modal from './modal'; +import { findAsync } from './find-async'; import * as debug from './debug'; import faker from 'faker'; +import { Application } from 'spectron'; -export const documentListingShown = async app => { +export const documentListingShown = async (app: Application) => { const item = await app.client.$('.document-listing'); await item.waitForExist(); }; -export const expectDocumentWithTitle = async (app, title) => { +export const expectDocumentWithTitle = async (app: Application, title: string) => { await app.client.waitUntilTextExists('.document-listing__body', title); }; -export const findCardWithTitle = async (app, text) => { +export const findCardWithTitle = async (app: Application, text: string) => { let card; await app.client.waitUntil(async () => { const cards = await app.client.react$$('Card'); @@ -26,60 +27,66 @@ export const findCardWithTitle = async (app, text) => { return card; }; -export const cardHasBadge = async (card, text) => { +// @ts-expect-error -- TSCONVERSION +export const cardHasBadge = async (card, text: string) => { const badge = await card.$('.header-item.card-badge'); expect(await badge.getText()).toBe(text); }; -export const openDocumentWithTitle = async (app, text) => { +export const openDocumentWithTitle = async (app: Application, text: string) => { const card = await findCardWithTitle(app, text); + // @ts-expect-error -- TSCONVERSION await card.waitForDisplayed(); + // @ts-expect-error -- TSCONVERSION await card.click(); await debug.pageDisplayed(app); }; -export const expectTotalDocuments = async (app, count) => { +export const expectTotalDocuments = async (app: Application, count: number) => { const label = count > 1 ? 'Documents' : 'Document'; await app.client.waitUntilTextExists('.document-listing__footer', `${count} ${label}`); }; +// @ts-expect-error -- TSCONVERSION don't happen to have this type handy (as far as I understand) export const openDocumentMenuDropdown = async card => { const dropdown = await card.react$('DocumentCardDropdown'); await dropdown.click(); }; -const openCreateDropdown = async app => { +const openCreateDropdown = async (app: Application) => { const button = await app.client.$('button*=Create'); await button.waitForClickable(); await button.click(); }; -export const createNewCollection = async (app, prefix = 'coll') => { +export const createNewCollection = async (app: Application, prefix = 'coll') => { await openCreateDropdown(app); await dropdown.clickDropdownItemByText(app.client, 'Request Collection'); const collectionName = `${prefix}-${faker.lorem.slug()}`; + // @ts-expect-error -- TSCONVERSION await modal.waitUntilOpened(app, { title: 'Create New Request Collection' }); await modal.typeIntoModalInput(app, collectionName); await modal.clickModalFooterByText(app, 'Create'); return collectionName; }; -export const createNewDocument = async (app, prefix = 'doc') => { +export const createNewDocument = async (app: Application, prefix = 'doc') => { await openCreateDropdown(app); await dropdown.clickDropdownItemByText(app.client, 'Design Document'); const documentName = `${prefix}-${faker.lorem.slug()}`; + // @ts-expect-error -- TSCONVERSION await modal.waitUntilOpened(app, { title: 'Create New Design Document' }); await modal.typeIntoModalInput(app, documentName); await modal.clickModalFooterByText(app, 'Create'); return documentName; }; -export const importFromClipboard = async app => { +export const importFromClipboard = async (app: Application) => { await openCreateDropdown(app); await dropdown.clickDropdownItemByText(app.client, 'Clipboard'); diff --git a/packages/insomnia-smoke-test/modules/migration.js b/packages/insomnia-smoke-test/src/modules/migration.ts similarity index 56% rename from packages/insomnia-smoke-test/modules/migration.js rename to packages/insomnia-smoke-test/src/modules/migration.ts index 768d11c7bfd..9c0a24c55ad 100644 --- a/packages/insomnia-smoke-test/modules/migration.js +++ b/packages/insomnia-smoke-test/src/modules/migration.ts @@ -1,40 +1,42 @@ -export const migrationMessageShown = async app => { +import { Application } from 'spectron'; + +export const migrationMessageShown = async (app: Application) => { await app.client.waitUntilTextExists( '.onboarding__content__header h1', 'Migrate from Insomnia Designer', ); }; -export const clickSkip = async app => { - const button = await app.client.react$('MigrationBody').then(e => e.$(`button=Skip for now`)); +export const clickSkip = async (app: Application) => { + const button = await app.client.react$('MigrationBody').then(e => e.$('button=Skip for now')); await button.waitForClickable(); await button.click(); }; -export const toggleOption = async (app, label) => { +export const toggleOption = async (app: Application, label: string) => { 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`)); +const _getStartButton = async (app: Application) => { + return await app.client.react$('MigrationBody').then(e => e.$('button=Start Migration')); }; -export const clickStart = async app => { +export const clickStart = async (app: Application) => { const button = await _getStartButton(app); await button.waitForClickable(); await button.click(); }; -export const ensureStartNotClickable = async app => { +export const ensureStartNotClickable = async (app: Application) => { const button = await _getStartButton(app); await button.waitForClickable({ reverse: true }); }; -export const successMessageShown = async app => { +export const successMessageShown = async (app: Application) => { await app.client.waitUntilTextExists( '.onboarding__content__body p strong', 'Migrated successfully!', @@ -42,9 +44,9 @@ export const successMessageShown = async app => { ); }; -export const clickRestart = async app => { +export const clickRestart = async (app: Application) => { await app.client .react$('MigrationBody') - .then(e => e.$(`button=Restart Now`)) + .then(e => e.$('button=Restart Now')) .then(e => e.click()); }; diff --git a/packages/insomnia-smoke-test/modules/modal.js b/packages/insomnia-smoke-test/src/modules/modal.ts similarity index 63% rename from packages/insomnia-smoke-test/modules/modal.js rename to packages/insomnia-smoke-test/src/modules/modal.ts index f849a37424a..6043d1d1dfa 100644 --- a/packages/insomnia-smoke-test/modules/modal.js +++ b/packages/insomnia-smoke-test/src/modules/modal.ts @@ -1,6 +1,7 @@ -import findAsync from './find-async'; +import { Application } from 'spectron'; +import { findAsync } from './find-async'; -export const waitUntilOpened = async (app, { modalName, title }) => { +export const waitUntilOpened = async (app: Application, { modalName, title }: { modalName: string, title: string }) => { if (modalName) { const modal = await app.client.react$(modalName); await modal.waitForDisplayed(); @@ -9,7 +10,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); @@ -21,7 +22,7 @@ export const close = async (app, modalName) => { await modal.$('button.modal__close-btn').then(e => e.click()); }; -export const clickModalFooterByText = async (app, text) => { +export const clickModalFooterByText = async (app: Application, text: string) => { const btn = await app.client .$('.modal[aria-hidden=false] .modal__footer') .then(e => e.$(`button*=${text}`)); @@ -29,8 +30,9 @@ export const clickModalFooterByText = async (app, text) => { await btn.click(); }; -export const typeIntoModalInput = async (app, text) => { +export const typeIntoModalInput = async (app: Application, text: string) => { const input = await app.client.$('.modal input'); await input.waitUntil(() => input.isFocused()); + // @ts-expect-error -- TSCONVERSION await input.keys(text); }; diff --git a/packages/insomnia-smoke-test/modules/onboarding.js b/packages/insomnia-smoke-test/src/modules/onboarding.ts similarity index 52% rename from packages/insomnia-smoke-test/modules/onboarding.js rename to packages/insomnia-smoke-test/src/modules/onboarding.ts index 00ae96812a2..46ea60f3501 100644 --- a/packages/insomnia-smoke-test/modules/onboarding.js +++ b/packages/insomnia-smoke-test/src/modules/onboarding.ts @@ -1,25 +1,27 @@ -const analyticsMessageShown = async app => { +import { Application } from 'spectron'; + +const analyticsMessageShown = async (app: Application) => { await app.client.waitUntilTextExists( '.onboarding__content__body p strong', 'Share Usage Analytics with Kong Inc', ); }; -const clickDontShare = async app => { +const clickDontShare = async (app: Application) => { 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 => { +const clickSkipImport = async (app: Application) => { await app.client .$('.onboarding__content__body') - .then(e => e.$(`button=Skip`)) + .then(e => e.$('button=Skip')) .then(e => e.click()); }; -export const skipOnboardingFlow = async app => { +export const skipOnboardingFlow = async (app: Application) => { await analyticsMessageShown(app); await clickDontShare(app); await clickSkipImport(app); diff --git a/packages/insomnia-smoke-test/modules/settings.js b/packages/insomnia-smoke-test/src/modules/settings.ts similarity index 85% rename from packages/insomnia-smoke-test/modules/settings.js rename to packages/insomnia-smoke-test/src/modules/settings.ts index 7021f802678..b395c0a907a 100644 --- a/packages/insomnia-smoke-test/modules/settings.js +++ b/packages/insomnia-smoke-test/src/modules/settings.ts @@ -2,18 +2,20 @@ import { clickTabByText } from './tabs'; import { mapAccelerator } from 'spectron-keys'; import * as modal from './modal'; import * as dropdown from './dropdown'; +import { Application } from 'spectron'; -export const openWithKeyboardShortcut = async app => { +export const openWithKeyboardShortcut = async (app: Application) => { await app.client.keys(mapAccelerator('CommandOrControl+,')); + // @ts-expect-error -- TSCONVERSION await modal.waitUntilOpened(app, { modalName: 'SettingsModal' }); }; -export const closeModal = async app => { +export const closeModal = async (app: Application) => { await modal.close(app, 'SettingsModal'); }; -export const goToPlugins = async app => { +export const goToPlugins = async (app: Application) => { // Click on the plugins tab await app.client.react$('SettingsModal').then(e => clickTabByText(e, 'Plugins')); @@ -21,7 +23,7 @@ export const goToPlugins = async app => { await app.client.react$('Plugins').then(e => e.waitForDisplayed()); }; -export const importFromClipboard = async (app, newWorkspace = false) => { +export const importFromClipboard = async (app: Application, newWorkspace = false) => { const importExport = await app.client.react$('ImportExport'); await importExport.waitForDisplayed(); @@ -36,7 +38,7 @@ export const importFromClipboard = async (app, newWorkspace = false) => { } }; -export const installPlugin = async (app, pluginName) => { +export const installPlugin = async (app: Application, pluginName: string) => { const plugins = await app.client.react$('SettingsModal').then(e => e.react$('Plugins')); // Find text input and install button diff --git a/packages/insomnia-smoke-test/src/modules/tabs.ts b/packages/insomnia-smoke-test/src/modules/tabs.ts new file mode 100644 index 00000000000..ceafa4f1ceb --- /dev/null +++ b/packages/insomnia-smoke-test/src/modules/tabs.ts @@ -0,0 +1,5 @@ +// @ts-expect-error -- TSCONVERSION as far as I know we dont this type handy +export const clickTabByText = async (element, text: string) => { + // @ts-expect-error -- TSCONVERSION + await element.$(`.react-tabs__tab=${text}`).then(e => e.click()); +}; diff --git a/packages/insomnia-smoke-test/server/index.js b/packages/insomnia-smoke-test/src/server/index.ts similarity index 90% rename from packages/insomnia-smoke-test/server/index.js rename to packages/insomnia-smoke-test/src/server/index.ts index f983da2d30d..0e87f41fe4f 100644 --- a/packages/insomnia-smoke-test/server/index.js +++ b/packages/insomnia-smoke-test/src/server/index.ts @@ -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); }); diff --git a/packages/insomnia-smoke-test/src/spectron-keys.d.ts b/packages/insomnia-smoke-test/src/spectron-keys.d.ts new file mode 100644 index 00000000000..f7aeb36ce14 --- /dev/null +++ b/packages/insomnia-smoke-test/src/spectron-keys.d.ts @@ -0,0 +1,4 @@ +declare module 'spectron-keys' { + type WebdriverReadyUnicodeAndKeys = [WebDriverReadyUnicode: string, keys: string]; + export const mapAccelerator: (accelerator: string, platform?: string) => WebdriverReadyUnicodeAndKeys; +} diff --git a/packages/insomnia-smoke-test/tsconfig.build.json b/packages/insomnia-smoke-test/tsconfig.build.json new file mode 100644 index 00000000000..8aba2e14806 --- /dev/null +++ b/packages/insomnia-smoke-test/tsconfig.build.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "dist", + "rootDir": "src", + "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 + }, + "include": [ + "src", + ], + "exclude": [ + "src/jest", + "**/*.test.ts", + ] +} \ No newline at end of file diff --git a/packages/insomnia-smoke-test/tsconfig.json b/packages/insomnia-smoke-test/tsconfig.json new file mode 100644 index 00000000000..93486d850b6 --- /dev/null +++ b/packages/insomnia-smoke-test/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { + "composite": false, + "rootDir": "." + }, + "include": [ + "src", + "jest.config.js", + ".eslintrc.js" + ], + "exclude": [ + "dist" + ] +}