From 2a6c9cd6c5e72367969c284b97e94874c07646f4 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 5 Sep 2022 18:28:53 +0100 Subject: [PATCH 1/8] QA Core repo, and Jest API tests running end to end --- .github/workflows/budibase_ci.yml | 12 +- .prettierignore | 2 +- package.json | 2 + packages/builder/cypress/setup.js | 6 + .../server/src/api/routes/tests/user.spec.js | 1 - packages/server/src/app.ts | 13 +- .../server/src/utilities/workerRequests.js | 8 + .../worker/src/api/controllers/global/self.js | 21 +- packages/worker/src/environment.ts | 1 + qa-core/.gitignore | 4 + qa-core/package.json | 52 + qa-core/scripts/jestSetup.js | 15 + qa-core/src/environment.ts | 8 + qa-core/src/jest.extends.ts | 22 + .../src/tests/public-api/PublicAPIClient.ts | 58 + .../src/tests/public-api/TestConfiguration.ts | 39 + .../applications/applications.spec.ts | 47 + .../applications/fixtures/application.json | 4 + .../applications/fixtures/generate.ts | 9 + .../applications/fixtures/seed.json | 4 + .../fixtures/update_application.json | 4 + qa-core/src/tests/public-api/generator.ts | 3 + .../tests/public-api/tables/fixtures/row.json | 8 + .../public-api/tables/fixtures/seed.json | 94 + .../public-api/tables/fixtures/table.json | 94 + .../tables/fixtures/update_row.json | 8 + .../tables/fixtures/update_table.json | 94 + .../src/tests/public-api/tables/rows.spec.ts | 51 + .../tests/public-api/tables/tables.spec.ts | 48 + .../public-api/users/fixtures/generate.ts | 22 + .../users/fixtures/update_user.json | 18 + .../tests/public-api/users/fixtures/user.json | 18 + .../src/tests/public-api/users/users.spec.ts | 46 + qa-core/tsconfig.json | 36 + qa-core/yarn.lock | 2658 +++++++++++++++++ 35 files changed, 3518 insertions(+), 12 deletions(-) create mode 100644 qa-core/.gitignore create mode 100644 qa-core/package.json create mode 100644 qa-core/scripts/jestSetup.js create mode 100644 qa-core/src/environment.ts create mode 100644 qa-core/src/jest.extends.ts create mode 100644 qa-core/src/tests/public-api/PublicAPIClient.ts create mode 100644 qa-core/src/tests/public-api/TestConfiguration.ts create mode 100644 qa-core/src/tests/public-api/applications/applications.spec.ts create mode 100644 qa-core/src/tests/public-api/applications/fixtures/application.json create mode 100644 qa-core/src/tests/public-api/applications/fixtures/generate.ts create mode 100644 qa-core/src/tests/public-api/applications/fixtures/seed.json create mode 100644 qa-core/src/tests/public-api/applications/fixtures/update_application.json create mode 100644 qa-core/src/tests/public-api/generator.ts create mode 100644 qa-core/src/tests/public-api/tables/fixtures/row.json create mode 100644 qa-core/src/tests/public-api/tables/fixtures/seed.json create mode 100644 qa-core/src/tests/public-api/tables/fixtures/table.json create mode 100644 qa-core/src/tests/public-api/tables/fixtures/update_row.json create mode 100644 qa-core/src/tests/public-api/tables/fixtures/update_table.json create mode 100644 qa-core/src/tests/public-api/tables/rows.spec.ts create mode 100644 qa-core/src/tests/public-api/tables/tables.spec.ts create mode 100644 qa-core/src/tests/public-api/users/fixtures/generate.ts create mode 100644 qa-core/src/tests/public-api/users/fixtures/update_user.json create mode 100644 qa-core/src/tests/public-api/users/fixtures/user.json create mode 100644 qa-core/src/tests/public-api/users/users.spec.ts create mode 100644 qa-core/tsconfig.json create mode 100644 qa-core/yarn.lock diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index e940e6fa10..df7a36caa4 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -54,8 +54,10 @@ jobs: verbose: true # TODO: parallelise this - - name: Cypress run - uses: cypress-io/github-action@v2 - with: - install: false - command: yarn test:e2e:ci + # - name: Cypress run + # uses: cypress-io/github-action@v2 + # with: + # install: false + # command: yarn test:e2e:ci + + - run: yarn test:api:ci \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index bbeff65da7..ad36a86b99 100644 --- a/.prettierignore +++ b/.prettierignore @@ -8,4 +8,4 @@ packages/server/client packages/server/src/definitions/openapi.ts packages/builder/.routify packages/builder/cypress/support/queryLevelTransformerFunction.js -packages/builder/cypress/support/queryLevelTransformerFunctionWithData.js +packages/builder/cypress/support/queryLevelTransformerFunctionWithData.js \ No newline at end of file diff --git a/package.json b/package.json index 4c24e0025b..a2d8f28f43 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,8 @@ "test:e2e:ci": "lerna run cy:ci --stream", "test:e2e:ci:record": "lerna run cy:ci:record --stream", "test:e2e:ci:notify": "lerna run cy:ci:notify", + "test:api:ci": "npm --prefix ./qa-core run api:test:ci", + "test:api": "npm --prefix ./qa-core run api:test", "build:specs": "lerna run specs", "build:docker": "lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh $BUDIBASE_RELEASE_VERSION && cd -", "build:docker:pre": "lerna run build && lerna run predocker", diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index d858801990..853cdfc14d 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -22,6 +22,12 @@ process.env.COUCH_DB_PASSWORD = "budibase" process.env.INTERNAL_API_KEY = "budibase" process.env.ALLOW_DEV_AUTOMATIONS = 1 +// TODO: inject at the qa-core level +process.env.BB_ADMIN_USER_EMAIL = "qa@budibase.com" +process.env.BB_ADMIN_USER_PASSWORD = "budibase" +process.env.ENCRYPTED_TEST_PUBLIC_API_KEY = + "a65722f06bee5caeadc5d7ca2f543a43-d610e627344210c643bb726f" + // Stop info logs polluting test outputs process.env.LOG_LEVEL = "error" diff --git a/packages/server/src/api/routes/tests/user.spec.js b/packages/server/src/api/routes/tests/user.spec.js index e699f818d6..a7f1e7e7dc 100644 --- a/packages/server/src/api/routes/tests/user.spec.js +++ b/packages/server/src/api/routes/tests/user.spec.js @@ -23,7 +23,6 @@ describe("/users", () => { }) describe("fetch", () => { - it("returns a list of users from an instance db", async () => { await config.createUser("uuidx") await config.createUser("uuidy") diff --git a/packages/server/src/app.ts b/packages/server/src/app.ts index 831a9b1046..9be8c78a66 100644 --- a/packages/server/src/app.ts +++ b/packages/server/src/app.ts @@ -29,7 +29,11 @@ const { Thread } = require("./threads") import redis from "./utilities/redis" import * as migrations from "./migrations" import { events, installation, tenancy } from "@budibase/backend-core" -import { createAdminUser, getChecklist } from "./utilities/workerRequests" +import { + createAdminUser, + generateApiKey, + getChecklist, +} from "./utilities/workerRequests" const app = new Koa() @@ -123,11 +127,16 @@ module.exports = server.listen(env.PORT || 0, async () => { if (!checklist?.adminUser?.checked) { try { const tenantId = tenancy.getTenantId() - await createAdminUser( + const user = await createAdminUser( env.BB_ADMIN_USER_EMAIL, env.BB_ADMIN_USER_PASSWORD, tenantId ) + // Need to set up an API key for automated integration tests + if (env.isTest()) { + await generateApiKey(user._id) + } + console.log( "Admin account automatically created for", env.BB_ADMIN_USER_EMAIL diff --git a/packages/server/src/utilities/workerRequests.js b/packages/server/src/utilities/workerRequests.js index cbecb2c4b5..e08ad147d1 100644 --- a/packages/server/src/utilities/workerRequests.js +++ b/packages/server/src/utilities/workerRequests.js @@ -153,3 +153,11 @@ exports.getChecklist = async () => { ) return checkResponse(response, "get checklist") } + +exports.generateApiKey = async userId => { + const response = await fetch( + checkSlashesInUrl(env.WORKER_URL + "/api/global/self/api_key"), + request(null, { method: "POST", body: { userId } }) + ) + return checkResponse(response, "generate API key") +} diff --git a/packages/worker/src/api/controllers/global/self.js b/packages/worker/src/api/controllers/global/self.js index 28afa69fa0..6824476af3 100644 --- a/packages/worker/src/api/controllers/global/self.js +++ b/packages/worker/src/api/controllers/global/self.js @@ -16,6 +16,11 @@ const { newid } = require("@budibase/backend-core/utils") const { users } = require("../../../sdk") const { Cookies } = require("@budibase/backend-core/constants") const { events, featureFlags } = require("@budibase/backend-core") +const env = require("../../../environment") + +function newTestApiKey() { + return env.ENCRYPTED_TEST_PUBLIC_API_KEY +} function newApiKey() { return encrypt(`${getTenantId()}${SEPARATOR}${newid()}`) @@ -29,15 +34,25 @@ function cleanupDevInfo(info) { } exports.generateAPIKey = async ctx => { + let userId + let apiKey + if (env.isTest() && ctx.request.body.userId) { + userId = ctx.request.body.userId + apiKey = newTestApiKey() + } else { + userId = ctx.user._id + apiKey = newApiKey() + } + const db = getGlobalDB() - const id = generateDevInfoID(ctx.user._id) + const id = generateDevInfoID(userId) let devInfo try { devInfo = await db.get(id) } catch (err) { - devInfo = { _id: id, userId: ctx.user._id } + devInfo = { _id: id, userId } } - devInfo.apiKey = await newApiKey() + devInfo.apiKey = await apiKey await db.put(devInfo) ctx.body = cleanupDevInfo(devInfo) } diff --git a/packages/worker/src/environment.ts b/packages/worker/src/environment.ts index fd6749a0f7..0d7853193b 100644 --- a/packages/worker/src/environment.ts +++ b/packages/worker/src/environment.ts @@ -62,6 +62,7 @@ const env = { // other CHECKLIST_CACHE_TTL: parseIntSafe(process.env.CHECKLIST_CACHE_TTL) || 3600, SESSION_UPDATE_PERIOD: process.env.SESSION_UPDATE_PERIOD, + ENCRYPTED_TEST_PUBLIC_API_KEY: process.env.ENCRYPTED_TEST_PUBLIC_API_KEY, _set(key: any, value: any) { process.env[key] = value module.exports[key] = value diff --git a/qa-core/.gitignore b/qa-core/.gitignore new file mode 100644 index 0000000000..e82880bc81 --- /dev/null +++ b/qa-core/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +.env +watchtower-hook.json +dist/ \ No newline at end of file diff --git a/qa-core/package.json b/qa-core/package.json new file mode 100644 index 0000000000..30d2fc9526 --- /dev/null +++ b/qa-core/package.json @@ -0,0 +1,52 @@ +{ + "name": "@budibase/qa-core", + "email": "hi@budibase.com", + "version": "0.0.1", + "main": "index.js", + "description": "Budibase Integration Test Suite", + "repository": { + "type": "git", + "url": "https://github.com/Budibase/budibase.git" + }, + "scripts": { + "test": "jest --runInBand", + "test:watch": "jest --watch", + "test:debug": "DEBUG=1 jest", + "api:server:setup": "ts-node ../packages/builder/cypress/ts/setup.ts", + "api:server:setup:ci": "node ../packages/builder/cypress/setup.js", + "api:test:ci": "start-server-and-test api:server:setup:ci http://localhost:4100/builder test", + "api:test": "start-server-and-test api:server:setup http://localhost:4100/builder test" + }, + "jest": { + "preset": "ts-jest", + "testEnvironment": "node", + "moduleNameMapper": { + "@budibase/backend-core/(.*)": "/../packages/backend-core/$1", + "@budibase/backend-core": "/../packages/backend-core/src", + "@budibase/types": "/../packages/types/src" + }, + "setupFiles": [ + "./scripts/jestSetup.js" + ], + "setupFilesAfterEnv": [ + "./src/jest.extends.ts" + ] + }, + "devDependencies": { + "@budibase/types": "^1.3.4", + "@types/jest": "^29.0.0", + "@types/node-fetch": "^2.6.2", + "chance": "^1.1.8", + "jest": "^28.0.2", + "prettier": "^2.7.1", + "start-server-and-test": "^1.14.0", + "timekeeper": "^2.2.0", + "ts-jest": "28.0.8", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.1.0", + "typescript": "^4.8.2" + }, + "dependencies": { + "node-fetch": "2" + } +} \ No newline at end of file diff --git a/qa-core/scripts/jestSetup.js b/qa-core/scripts/jestSetup.js new file mode 100644 index 0000000000..5902a68af7 --- /dev/null +++ b/qa-core/scripts/jestSetup.js @@ -0,0 +1,15 @@ +const env = require("../src/environment") + +env._set("BUDIBASE_SERVER_URL", "http://localhost:4100") +env._set("BUDIBASE_PUBLIC_API_KEY", "a65722f06bee5caeadc5d7ca2f543a43-d610e627344210c643bb726f") + +// mock all dates to 2020-01-01T00:00:00.000Z +// use tk.reset() to use real dates in individual tests +const MOCK_DATE = new Date("2020-01-01T00:00:00.000Z") +const MOCK_DATE_TIMESTAMP = 1577836800000 +const tk = require("timekeeper") +tk.freeze(MOCK_DATE) + +if (!process.env.DEBUG) { + global.console.log = jest.fn() // console.log are ignored in tests +} diff --git a/qa-core/src/environment.ts b/qa-core/src/environment.ts new file mode 100644 index 0000000000..4ef8de795a --- /dev/null +++ b/qa-core/src/environment.ts @@ -0,0 +1,8 @@ +export = { + BUDIBASE_SERVER_URL: process.env.BUDIBASE_SERVER_URL, + BUDIBASE_PUBLIC_API_KEY: process.env.BUDIBASE_PUBLIC_API_KEY, + _set(key: any, value: any) { + process.env[key] = value + module.exports[key] = value + }, +} \ No newline at end of file diff --git a/qa-core/src/jest.extends.ts b/qa-core/src/jest.extends.ts new file mode 100644 index 0000000000..380bf85c81 --- /dev/null +++ b/qa-core/src/jest.extends.ts @@ -0,0 +1,22 @@ +// boilerplate to allow TS updates to the global scope +export {}; + +declare global { + namespace jest { + interface Matchers { + toHaveStatusCode(code: number): R; + } + } +} + +// Expect extensions +expect.extend({ + toHaveStatusCode(received, code) { + const pass = received.status === code + return { + message: () => + `expected ${received.status} to match status code ${code}`, + pass, + } + }, +}) diff --git a/qa-core/src/tests/public-api/PublicAPIClient.ts b/qa-core/src/tests/public-api/PublicAPIClient.ts new file mode 100644 index 0000000000..017d8088dd --- /dev/null +++ b/qa-core/src/tests/public-api/PublicAPIClient.ts @@ -0,0 +1,58 @@ +import env from "../../environment" +import fetch from "node-fetch" + +interface HeaderOptions { + headers?: object; + body?: object; + json?: boolean; +} + +type APIMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" + +class PublicAPIClient { + host: string + apiKey: string + appId?: string + + constructor(appId?: string) { + if (!env.BUDIBASE_PUBLIC_API_KEY || !env.BUDIBASE_SERVER_URL) { + throw new Error("Must set BUDIBASE_PUBLIC_API_KEY and BUDIBASE_SERVER_URL env vars") + } + this.host = `${env.BUDIBASE_SERVER_URL}/api/public/v1` + this.apiKey = env.BUDIBASE_PUBLIC_API_KEY + this.appId = appId + } + + apiCall = + (method: APIMethod) => + async (url = "", options: HeaderOptions = {}) => { + const requestOptions = { + method: method, + body: JSON.stringify(options.body), + headers: { + "x-budibase-api-key": this.apiKey, + "x-budibase-app-id": this.appId, + "Content-Type": "application/json", + Accept: "application/json", + ...options.headers, + }, + // TODO: See if this is necessary + credentials: "include", + } + + // @ts-ignore + const response = await fetch(`${this.host}${url}`, requestOptions) + if (response.status !== 200) { + console.error(response) + } + return response + } + + post = this.apiCall("POST") + get = this.apiCall("GET") + patch = this.apiCall("PATCH") + del = this.apiCall("DELETE") + put = this.apiCall("PUT") +} + +export default PublicAPIClient \ No newline at end of file diff --git a/qa-core/src/tests/public-api/TestConfiguration.ts b/qa-core/src/tests/public-api/TestConfiguration.ts new file mode 100644 index 0000000000..647e64758e --- /dev/null +++ b/qa-core/src/tests/public-api/TestConfiguration.ts @@ -0,0 +1,39 @@ +import PublicAPIClient from "./PublicAPIClient"; +import generateApp from "./applications/fixtures/generate" + +class TestConfiguration { + testContext: Record; + apiClient: PublicAPIClient; + + constructor() { + this.testContext = {} + this.apiClient = new PublicAPIClient() + } + + async beforeAll() { + + } + + async afterAll() { + } + + async seedTable(appId: string) { + const response = await this.apiClient.post("/tables", { + body: require("./tables/fixtures/seed.json"), + headers: { + "x-budibase-app-id": appId + } + }) + const json = await response.json() + return json.data + } + + async seedApp() { + const response = await this.apiClient.post("/applications", { + body: generateApp() + }) + return response.json() + } +} + +export default TestConfiguration diff --git a/qa-core/src/tests/public-api/applications/applications.spec.ts b/qa-core/src/tests/public-api/applications/applications.spec.ts new file mode 100644 index 0000000000..83180429e0 --- /dev/null +++ b/qa-core/src/tests/public-api/applications/applications.spec.ts @@ -0,0 +1,47 @@ +import TestConfiguration from "../TestConfiguration" +import PublicAPIClient from "../PublicAPIClient" +import generateApp from "./fixtures/generate" + +describe("Public API - /applications endpoints", () => { + const api = new PublicAPIClient() + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("POST - Create a application", async () => { + const response = await api.post(`/applications`, { + body: generateApp() + }) + const json = await response.json() + config.testContext.application = json.data + expect(response).toHaveStatusCode(200) + }) + + it("POST - Search applications", async () => { + const response = await api.post(`/applications/search`, { + body: { + name: config.testContext.application.name + } + }) + expect(response).toHaveStatusCode(200) + }) + + it("GET - Retrieve a application", async () => { + const response = await api.get(`/applications/${config.testContext.application._id}`) + expect(response).toHaveStatusCode(200) + }) + + + it("PUT - update a application", async () => { + const response = await api.put(`/applications/${config.testContext.application._id}`, { + body: require("./fixtures/update_application.json") + }) + expect(response).toHaveStatusCode(200) + }) +}) diff --git a/qa-core/src/tests/public-api/applications/fixtures/application.json b/qa-core/src/tests/public-api/applications/fixtures/application.json new file mode 100644 index 0000000000..093edbcb0e --- /dev/null +++ b/qa-core/src/tests/public-api/applications/fixtures/application.json @@ -0,0 +1,4 @@ +{ + "name": "TestApp", + "url": "/testapp" +} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/applications/fixtures/generate.ts b/qa-core/src/tests/public-api/applications/fixtures/generate.ts new file mode 100644 index 0000000000..2e28f6fb06 --- /dev/null +++ b/qa-core/src/tests/public-api/applications/fixtures/generate.ts @@ -0,0 +1,9 @@ +import generator from "../../generator" + +const generate = (overrides = {}) => ({ + name: generator.word(), + url: `/${generator.word()}`, + ...overrides +}) + +export default generate \ No newline at end of file diff --git a/qa-core/src/tests/public-api/applications/fixtures/seed.json b/qa-core/src/tests/public-api/applications/fixtures/seed.json new file mode 100644 index 0000000000..7a5de02e82 --- /dev/null +++ b/qa-core/src/tests/public-api/applications/fixtures/seed.json @@ -0,0 +1,4 @@ +{ + "name": "SeedApp", + "url": "/seedapp" +} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/applications/fixtures/update_application.json b/qa-core/src/tests/public-api/applications/fixtures/update_application.json new file mode 100644 index 0000000000..ea3b3d0b31 --- /dev/null +++ b/qa-core/src/tests/public-api/applications/fixtures/update_application.json @@ -0,0 +1,4 @@ +{ + "name": "UpdatedTestApp", + "url": "/updatedtestapp" +} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/generator.ts b/qa-core/src/tests/public-api/generator.ts new file mode 100644 index 0000000000..f9ef06f243 --- /dev/null +++ b/qa-core/src/tests/public-api/generator.ts @@ -0,0 +1,3 @@ +const Chance = require("chance") + +export default new Chance() \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/fixtures/row.json b/qa-core/src/tests/public-api/tables/fixtures/row.json new file mode 100644 index 0000000000..9436576947 --- /dev/null +++ b/qa-core/src/tests/public-api/tables/fixtures/row.json @@ -0,0 +1,8 @@ +{ + "type": "row", + "tableId": "seed_table", + "sasa": "Mike", + "relationship": [ + "ro_ta_" + ] +} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/fixtures/seed.json b/qa-core/src/tests/public-api/tables/fixtures/seed.json new file mode 100644 index 0000000000..acbaeaff6c --- /dev/null +++ b/qa-core/src/tests/public-api/tables/fixtures/seed.json @@ -0,0 +1,94 @@ +{ + "name": "test", + "primaryDisplay": "sasa", + "schema": { + "Auto ID": { + "autocolumn": true, + "constraints": { + "numericality": { + "greaterThanOrEqualTo": "", + "lessThanOrEqualTo": "" + }, + "presence": false, + "type": "number" + }, + "icon": "ri-magic-line", + "name": "Auto ID", + "subtype": "autoID", + "type": "number" + }, + "Created At": { + "autocolumn": true, + "constraints": { + "datetime": { + "earliest": "", + "latest": "" + }, + "length": {}, + "presence": false, + "type": "string" + }, + "icon": "ri-magic-line", + "name": "Created At", + "subtype": "createdAt", + "type": "datetime" + }, + "Created By": { + "autocolumn": true, + "constraints": { + "presence": false, + "type": "array" + }, + "fieldName": "test12-Created By", + "icon": "ri-magic-line", + "name": "Created By", + "relationshipType": "many-to-many", + "subtype": "createdBy", + "tableId": "ta_users", + "type": "link" + }, + "sasa": { + "constraints": { + "length": { + "maximum": null + }, + "presence": { + "allowEmpty": false + }, + "type": "string" + }, + "name": "sasa", + "type": "string" + }, + "Updated At": { + "autocolumn": true, + "constraints": { + "datetime": { + "earliest": "", + "latest": "" + }, + "length": {}, + "presence": false, + "type": "string" + }, + "icon": "ri-magic-line", + "name": "Updated At", + "subtype": "updatedAt", + "type": "datetime" + }, + "Updated By": { + "autocolumn": true, + "constraints": { + "presence": false, + "type": "array" + }, + "fieldName": "test12-Updated By", + "icon": "ri-magic-line", + "name": "Updated By", + "relationshipType": "many-to-many", + "subtype": "updatedBy", + "tableId": "ta_users", + "type": "link" + } + } +} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/fixtures/table.json b/qa-core/src/tests/public-api/tables/fixtures/table.json new file mode 100644 index 0000000000..acbaeaff6c --- /dev/null +++ b/qa-core/src/tests/public-api/tables/fixtures/table.json @@ -0,0 +1,94 @@ +{ + "name": "test", + "primaryDisplay": "sasa", + "schema": { + "Auto ID": { + "autocolumn": true, + "constraints": { + "numericality": { + "greaterThanOrEqualTo": "", + "lessThanOrEqualTo": "" + }, + "presence": false, + "type": "number" + }, + "icon": "ri-magic-line", + "name": "Auto ID", + "subtype": "autoID", + "type": "number" + }, + "Created At": { + "autocolumn": true, + "constraints": { + "datetime": { + "earliest": "", + "latest": "" + }, + "length": {}, + "presence": false, + "type": "string" + }, + "icon": "ri-magic-line", + "name": "Created At", + "subtype": "createdAt", + "type": "datetime" + }, + "Created By": { + "autocolumn": true, + "constraints": { + "presence": false, + "type": "array" + }, + "fieldName": "test12-Created By", + "icon": "ri-magic-line", + "name": "Created By", + "relationshipType": "many-to-many", + "subtype": "createdBy", + "tableId": "ta_users", + "type": "link" + }, + "sasa": { + "constraints": { + "length": { + "maximum": null + }, + "presence": { + "allowEmpty": false + }, + "type": "string" + }, + "name": "sasa", + "type": "string" + }, + "Updated At": { + "autocolumn": true, + "constraints": { + "datetime": { + "earliest": "", + "latest": "" + }, + "length": {}, + "presence": false, + "type": "string" + }, + "icon": "ri-magic-line", + "name": "Updated At", + "subtype": "updatedAt", + "type": "datetime" + }, + "Updated By": { + "autocolumn": true, + "constraints": { + "presence": false, + "type": "array" + }, + "fieldName": "test12-Updated By", + "icon": "ri-magic-line", + "name": "Updated By", + "relationshipType": "many-to-many", + "subtype": "updatedBy", + "tableId": "ta_users", + "type": "link" + } + } +} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/fixtures/update_row.json b/qa-core/src/tests/public-api/tables/fixtures/update_row.json new file mode 100644 index 0000000000..556e02f8bd --- /dev/null +++ b/qa-core/src/tests/public-api/tables/fixtures/update_row.json @@ -0,0 +1,8 @@ +{ + "type": "row", + "tableId": "seed_table", + "sasa": "MikeIsTheBest", + "relationship": [ + "ro_ta_..." + ] +} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/fixtures/update_table.json b/qa-core/src/tests/public-api/tables/fixtures/update_table.json new file mode 100644 index 0000000000..64ca1147e8 --- /dev/null +++ b/qa-core/src/tests/public-api/tables/fixtures/update_table.json @@ -0,0 +1,94 @@ +{ + "name": "test123", + "primaryDisplay": "sasa", + "schema": { + "Auto ID": { + "autocolumn": true, + "constraints": { + "numericality": { + "greaterThanOrEqualTo": "", + "lessThanOrEqualTo": "" + }, + "presence": false, + "type": "number" + }, + "icon": "ri-magic-line", + "name": "Auto ID", + "subtype": "autoID", + "type": "number" + }, + "Created At": { + "autocolumn": true, + "constraints": { + "datetime": { + "earliest": "", + "latest": "" + }, + "length": {}, + "presence": false, + "type": "string" + }, + "icon": "ri-magic-line", + "name": "Created At", + "subtype": "createdAt", + "type": "datetime" + }, + "Created By": { + "autocolumn": true, + "constraints": { + "presence": false, + "type": "array" + }, + "fieldName": "test12-Created By", + "icon": "ri-magic-line", + "name": "Created By", + "relationshipType": "many-to-many", + "subtype": "createdBy", + "tableId": "ta_users", + "type": "link" + }, + "sasa": { + "constraints": { + "length": { + "maximum": null + }, + "presence": { + "allowEmpty": false + }, + "type": "string" + }, + "name": "sasa", + "type": "string" + }, + "Updated At": { + "autocolumn": true, + "constraints": { + "datetime": { + "earliest": "", + "latest": "" + }, + "length": {}, + "presence": false, + "type": "string" + }, + "icon": "ri-magic-line", + "name": "Updated At", + "subtype": "updatedAt", + "type": "datetime" + }, + "Updated By": { + "autocolumn": true, + "constraints": { + "presence": false, + "type": "array" + }, + "fieldName": "test12-Updated By", + "icon": "ri-magic-line", + "name": "Updated By", + "relationshipType": "many-to-many", + "subtype": "updatedBy", + "tableId": "ta_users", + "type": "link" + } + } +} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/rows.spec.ts b/qa-core/src/tests/public-api/tables/rows.spec.ts new file mode 100644 index 0000000000..099a3d3593 --- /dev/null +++ b/qa-core/src/tests/public-api/tables/rows.spec.ts @@ -0,0 +1,51 @@ +import TestConfiguration from "../TestConfiguration" +import PublicAPIClient from "../PublicAPIClient" + +describe("Public API - /rows endpoints", () => { + let api: PublicAPIClient + + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + const app = await config.seedApp() + + config.testContext.table = await config.seedTable(app.data._id) + api = new PublicAPIClient(app.data._id) + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("POST - Create a row", async () => { + const response = await api.post(`/tables/${config.testContext.table._id}/rows`, { + body: require("./fixtures/row.json") + }) + const json = await response.json() + config.testContext.row = json.data + expect(response).toHaveStatusCode(200) + }) + + it("POST - Search rows", async () => { + const response = await api.post(`/tables/${config.testContext.table._id}/rows/search`, { + body: { + name: config.testContext.row.name + } + }) + expect(response).toHaveStatusCode(200) + }) + + it("GET - Retrieve a row", async () => { + const response = await api.get(`/tables/${config.testContext.table._id}/rows/${config.testContext.row._id}`) + expect(response).toHaveStatusCode(200) + }) + + + it("PUT - update a row", async () => { + const response = await api.put(`/tables/${config.testContext.table._id}/rows/${config.testContext.row._id}`, { + body: require("./fixtures/update_row.json") + }) + expect(response).toHaveStatusCode(200) + }) +}) diff --git a/qa-core/src/tests/public-api/tables/tables.spec.ts b/qa-core/src/tests/public-api/tables/tables.spec.ts new file mode 100644 index 0000000000..70e3bb8d78 --- /dev/null +++ b/qa-core/src/tests/public-api/tables/tables.spec.ts @@ -0,0 +1,48 @@ +import TestConfiguration from "../TestConfiguration" +import PublicAPIClient from "../PublicAPIClient" + +describe("Public API - /tables endpoints", () => { + let api: PublicAPIClient + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + const app = await config.seedApp() + api = new PublicAPIClient(app.data._id) + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("POST - Create a table", async () => { + const response = await api.post(`/tables`, { + body: require("./fixtures/table.json") + }) + const json = await response.json() + config.testContext.table = json.data + expect(response).toHaveStatusCode(200) + }) + + it("POST - Search tables", async () => { + const response = await api.post(`/tables/search`, { + body: { + name: config.testContext.table.name + } + }) + expect(response).toHaveStatusCode(200) + }) + + it("GET - Retrieve a table", async () => { + const response = await api.get(`/tables/${config.testContext.table._id}`) + expect(response).toHaveStatusCode(200) + }) + + + it("PUT - update a table", async () => { + const response = await api.put(`/tables/${config.testContext.table._id}`, { + body: require("./fixtures/update_table.json") + }) + expect(response).toHaveStatusCode(200) + }) +}) diff --git a/qa-core/src/tests/public-api/users/fixtures/generate.ts b/qa-core/src/tests/public-api/users/fixtures/generate.ts new file mode 100644 index 0000000000..ca3c7b3c2c --- /dev/null +++ b/qa-core/src/tests/public-api/users/fixtures/generate.ts @@ -0,0 +1,22 @@ +import generator from "../../generator" +import { User } from "@budibase/types" + +const generate = (overrides = {}): User => ({ + tenantId: generator.word(), + email: generator.email(), + roles: { + [generator.string({ length: 32, alpha: true, numeric: true })]: generator.word(), + }, + password: generator.word(), + status: "active", + forceResetPassword: generator.bool(), + builder: { + global: generator.bool() + }, + admin: { + global: generator.bool() + }, + ...overrides +}) + +export default generate \ No newline at end of file diff --git a/qa-core/src/tests/public-api/users/fixtures/update_user.json b/qa-core/src/tests/public-api/users/fixtures/update_user.json new file mode 100644 index 0000000000..72d24b3ee8 --- /dev/null +++ b/qa-core/src/tests/public-api/users/fixtures/update_user.json @@ -0,0 +1,18 @@ +{ + "email": "test@budibase.com", + "roles": { + "sed_6d7": "sit ea amet", + "cupidatat_e16": "fugiat proident sed" + }, + "password": "cupidatat Lorem ad", + "status": "active", + "firstName": "QA", + "lastName": "Updated", + "forceResetPassword": true, + "builder": { + "global": true + }, + "admin": { + "global": false + } +} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/users/fixtures/user.json b/qa-core/src/tests/public-api/users/fixtures/user.json new file mode 100644 index 0000000000..b6fc9f49e6 --- /dev/null +++ b/qa-core/src/tests/public-api/users/fixtures/user.json @@ -0,0 +1,18 @@ +{ + "email": "test@budibase.com", + "roles": { + "sed_6d7": "sit ea amet", + "cupidatat_e16": "fugiat proident sed" + }, + "password": "cupidatat Lorem ad", + "status": "active", + "firstName": "QA", + "lastName": "Test", + "forceResetPassword": true, + "builder": { + "global": true + }, + "admin": { + "global": false + } +} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/users/users.spec.ts b/qa-core/src/tests/public-api/users/users.spec.ts new file mode 100644 index 0000000000..c18a78ca72 --- /dev/null +++ b/qa-core/src/tests/public-api/users/users.spec.ts @@ -0,0 +1,46 @@ +import TestConfiguration from "../TestConfiguration" +import PublicAPIClient from "../PublicAPIClient" + +describe("Public API - /users endpoints", () => { + const api = new PublicAPIClient() + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("POST - Create a user", async () => { + const response = await api.post(`/users`, { + body: require("./fixtures/user.json") + }) + const json = await response.json() + config.testContext.user = json.data + expect(response).toHaveStatusCode(200) + }) + + it("POST - Search users", async () => { + const response = await api.post(`/users/search`, { + body: { + name: config.testContext.user.email + } + }) + expect(response).toHaveStatusCode(200) + }) + + it("GET - Retrieve a user", async () => { + const response = await api.get(`/users/${config.testContext.user._id}`) + expect(response).toHaveStatusCode(200) + }) + + + it("PUT - update a user", async () => { + const response = await api.put(`/users/${config.testContext.user._id}`, { + body: require("./fixtures/update_user.json") + }) + expect(response).toHaveStatusCode(200) + }) +}) diff --git a/qa-core/tsconfig.json b/qa-core/tsconfig.json new file mode 100644 index 0000000000..c305c3a4bd --- /dev/null +++ b/qa-core/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "lib": ["es2020"], + "allowJs": true, + "strict": true, + "noImplicitAny": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "incremental": true, + "types": ["node", "jest"], + "outDir": "dist", + "skipLibCheck": true, + "paths": { + "@budibase/types": ["../packages/types/src"], + "@budibase/backend-core": ["../packages/backend-core/src"], + "@budibase/backend-core/*": ["../packages/backend-core/*"] + } + }, + "ts-node": { + "require": ["tsconfig-paths/register"] + }, + "references": [ + { "path": "../packages/types" }, + { "path": "../packages/backend-core" }, + ], + "include": [ + "src/**/*", + "package.json" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/qa-core/yarn.lock b/qa-core/yarn.lock new file mode 100644 index 0000000000..5daa4d7ee7 --- /dev/null +++ b/qa-core/yarn.lock @@ -0,0 +1,2658 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.18.8": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.13.tgz#6aff7b350a1e8c3e40b029e46cbe78e24a913483" + integrity sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.13.tgz#9be8c44512751b05094a4d3ab05fc53a47ce00ac" + integrity sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.13" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-module-transforms" "^7.18.9" + "@babel/helpers" "^7.18.9" + "@babel/parser" "^7.18.13" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.18.13" + "@babel/types" "^7.18.13" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/generator@^7.18.13", "@babel/generator@^7.7.2": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.13.tgz#59550cbb9ae79b8def15587bdfbaa388c4abf212" + integrity sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ== + dependencies: + "@babel/types" "^7.18.13" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf" + integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg== + dependencies: + "@babel/compat-data" "^7.18.8" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.20.2" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0" + integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A== + dependencies: + "@babel/template" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712" + integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.8.0": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f" + integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w== + +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" + integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== + +"@babel/helper-validator-identifier@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076" + integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helpers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9" + integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ== + dependencies: + "@babel/template" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.18.13": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.13.tgz#5b2dd21cae4a2c5145f1fbd8ca103f9313d3b7e4" + integrity sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz#1c09cd25795c7c2b8a4ba9ae49394576d4133285" + integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/template@^7.18.10", "@babel/template@^7.18.6", "@babel/template@^7.3.3": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" + +"@babel/traverse@^7.18.13", "@babel/traverse@^7.18.9", "@babel/traverse@^7.7.2": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.13.tgz#5ab59ef51a997b3f10c4587d648b9696b6cb1a68" + integrity sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.18.13" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.18.13" + "@babel/types" "^7.18.13" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.13", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.13.tgz#30aeb9e514f4100f7c1cb6e5ba472b30e48f519a" + integrity sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ== + dependencies: + "@babel/helper-string-parser" "^7.18.10" + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@budibase/types@^1.3.4": + version "1.3.4" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.3.4.tgz#25f087b024e843eb372e50c81f8f925fb39f1dfd" + integrity sha512-ndyWs8yeCS7cpZjApDB1HhY6UUM2SRBUgAMCZOZaWABG9JHeCbx7x0e/pA2SZjswdMXqS5WmnEd3br5wuvUzJw== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@hapi/hoek@^9.0.0": + version "9.3.0" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" + integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== + +"@hapi/topo@^5.0.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.3.tgz#2030606ec03a18c31803b8a36382762e447655df" + integrity sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + +"@jest/core@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.3.tgz#0ebf2bd39840f1233cd5f2d1e6fc8b71bd5a1ac7" + integrity sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/reporters" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^28.1.3" + jest-config "^28.1.3" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-resolve-dependencies "^28.1.3" + jest-runner "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + jest-watcher "^28.1.3" + micromatch "^4.0.4" + pretty-format "^28.1.3" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.3.tgz#abed43a6b040a4c24fdcb69eab1f97589b2d663e" + integrity sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA== + dependencies: + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + +"@jest/expect-utils@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-28.1.3.tgz#58561ce5db7cd253a7edddbc051fb39dda50f525" + integrity sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA== + dependencies: + jest-get-type "^28.0.2" + +"@jest/expect-utils@^29.0.2": + version "29.0.2" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.0.2.tgz#00dfcb9e6fe99160c326ba39f7734b984543dea8" + integrity sha512-+wcQF9khXKvAEi8VwROnCWWmHfsJYCZAs5dmuMlJBKk57S6ZN2/FQMIlo01F29fJyT8kV/xblE7g3vkIdTLOjw== + dependencies: + jest-get-type "^29.0.0" + +"@jest/expect@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.3.tgz#9ac57e1d4491baca550f6bdbd232487177ad6a72" + integrity sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw== + dependencies: + expect "^28.1.3" + jest-snapshot "^28.1.3" + +"@jest/fake-timers@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.3.tgz#230255b3ad0a3d4978f1d06f70685baea91c640e" + integrity sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw== + dependencies: + "@jest/types" "^28.1.3" + "@sinonjs/fake-timers" "^9.1.2" + "@types/node" "*" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-util "^28.1.3" + +"@jest/globals@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.3.tgz#a601d78ddc5fdef542728309894895b4a42dc333" + integrity sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/types" "^28.1.3" + +"@jest/reporters@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.3.tgz#9adf6d265edafc5fc4a434cfb31e2df5a67a369a" + integrity sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + jest-worker "^28.1.3" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + terminal-link "^2.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.1.3.tgz#ad8b86a66f11f33619e3d7e1dcddd7f2d40ff905" + integrity sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg== + dependencies: + "@sinclair/typebox" "^0.24.1" + +"@jest/schemas@^29.0.0": + version "29.0.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.0.0.tgz#5f47f5994dd4ef067fb7b4188ceac45f77fe952a" + integrity sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA== + dependencies: + "@sinclair/typebox" "^0.24.1" + +"@jest/source-map@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24" + integrity sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww== + dependencies: + "@jridgewell/trace-mapping" "^0.3.13" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.3.tgz#5eae945fd9f4b8fcfce74d239e6f725b6bf076c5" + integrity sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg== + dependencies: + "@jest/console" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz#9d0c283d906ac599c74bde464bc0d7e6a82886c3" + integrity sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw== + dependencies: + "@jest/test-result" "^28.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + slash "^3.0.0" + +"@jest/transform@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.3.tgz#59d8098e50ab07950e0f2fc0fc7ec462371281b0" + integrity sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^28.1.3" + "@jridgewell/trace-mapping" "^0.3.13" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.1" + +"@jest/types@^28.1.3": + version "28.1.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.3.tgz#b05de80996ff12512bc5ceb1d208285a7d11748b" + integrity sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ== + dependencies: + "@jest/schemas" "^28.1.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jest/types@^29.0.2": + version "29.0.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.0.2.tgz#5a5391fa7f7f41bf4b201d6d2da30e874f95b6c1" + integrity sha512-5WNMesBLmlkt1+fVkoCjHa0X3i3q8zc4QLTDkdHgCa2gyPZc7rdlZBWgVLqwS1860ZW5xJuCDwAzqbGaXIr/ew== + dependencies: + "@jest/schemas" "^29.0.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.15" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" + integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@sideway/address@^4.1.3": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" + integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" + integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + +"@sinclair/typebox@^0.24.1": + version "0.24.35" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.35.tgz#7b5ca127aefe3ed482bb60f874bebbe3143e82f5" + integrity sha512-iN6ehuDndiTiDz2F+Orv/+oHJR+PrGv+38oghCddpsW4YEZl5qyLsWxSwYUWrKEOfjpGtXDFW6scJtjpzSLeSw== + +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^9.1.2": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" + integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + +"@types/babel__core@^7.1.14": + version "7.1.19" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" + integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.18.1" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.1.tgz#ce5e2c8c272b99b7a9fd69fa39f0b4cd85028bd9" + integrity sha512-FSdLaZh2UxaMuLp9lixWaHq/golWTRWOnRsAXzDTDSDOQLuZb1nsdCt6pJSPWSEQt2eFZ2YVk3oYhn+1kLMeMA== + dependencies: + "@babel/types" "^7.3.0" + +"@types/graceful-fs@^4.1.3": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.0.0": + version "29.0.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.0.0.tgz#bc66835bf6b09d6a47e22c21d7f5b82692e60e72" + integrity sha512-X6Zjz3WO4cT39Gkl0lZ2baFRaEMqJl5NC1OjElkwtNzAlbkr2K/WJXkBkH5VP0zx4Hgsd2TZYdOEfvp2Dxia+Q== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/node-fetch@^2.6.2": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" + integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + +"@types/node@*": + version "18.7.14" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.14.tgz#0fe081752a3333392d00586d815485a17c2cf3c9" + integrity sha512-6bbDaETVi8oyIARulOE9qF1/Qdi/23z6emrUh0fNJRUmjznqrixD4MpGDdgOFk5Xb0m2H6Xu42JGdvAxaJR/wA== + +"@types/prettier@^2.1.5": + version "2.7.0" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.0.tgz#ea03e9f0376a4446f44797ca19d9c46c36e352dc" + integrity sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^17.0.8": + version "17.0.12" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.12.tgz#0745ff3e4872b4ace98616d4b7e37ccbd75f9526" + integrity sha512-Nz4MPhecOFArtm81gFQvQqdV7XYCrWKx5uUt6GNHredFHn1i2mtWqXTON7EPXMtNi1qjtjEM/VCHDhcHsAMLXQ== + dependencies: + "@types/yargs-parser" "*" + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.4.1: + version "8.8.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + +babel-jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.3.tgz#c1187258197c099072156a0a121c11ee1e3917d5" + integrity sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q== + dependencies: + "@jest/transform" "^28.1.3" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^28.1.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz#1952c4d0ea50f2d6d794353762278d1d8cca3fbe" + integrity sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz#5dfc20b99abed5db994406c2b9ab94c73aaa419d" + integrity sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A== + dependencies: + babel-plugin-jest-hoist "^28.1.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +bluebird@3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.20.2: + version "4.21.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a" + integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ== + dependencies: + caniuse-lite "^1.0.30001370" + electron-to-chromium "^1.4.202" + node-releases "^2.0.6" + update-browserslist-db "^1.0.5" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001370: + version "1.0.30001390" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001390.tgz#158a43011e7068ef7fc73590e9fd91a7cece5e7f" + integrity sha512-sS4CaUM+/+vqQUlCvCJ2WtDlV81aWtHhqeEVkLokVJJa3ViN4zDxAGfq9R8i1m90uGHxo99cy10Od+lvn3hf0g== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chance@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/chance/-/chance-1.1.8.tgz#5d6c2b78c9170bf6eb9df7acdda04363085be909" + integrity sha512-v7fi5Hj2VbR6dJEGRWLmJBA83LJMS47pkAbmROFxHWd9qmE1esHRZW8Clf1Fhzr3rjxnNZVCjOEv/ivFxeIMtg== + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +check-more-types@2.24.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" + integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== + +ci-info@^3.2.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" + integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + +debug@^4.1.0, debug@^4.1.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" + integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== + +diff-sequences@^29.0.0: + version "29.0.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.0.0.tgz#bae49972ef3933556bcb0800b72e8579d19d9e4f" + integrity sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +duplexer@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +electron-to-chromium@^1.4.202: + version "1.4.241" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.241.tgz#5aa03ab94db590d8269f4518157c24b1efad34d6" + integrity sha512-e7Wsh4ilaioBZ5bMm6+F4V5c11dh56/5Jwz7Hl5Tu1J7cnB+Pqx5qIF2iC7HPpfyQMqGSvvLP5bBAIDd2gAtGw== + +emittery@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" + integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +event-stream@=3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + integrity sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g== + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + +execa@5.1.1, execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/expect/-/expect-28.1.3.tgz#90a7c1a124f1824133dd4533cce2d2bdcb6603ec" + integrity sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g== + dependencies: + "@jest/expect-utils" "^28.1.3" + jest-get-type "^28.0.2" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + +expect@^29.0.0: + version "29.0.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.0.2.tgz#22c7132400f60444b427211f1d6bb604a9ab2420" + integrity sha512-JeJlAiLKn4aApT4pzUXBVxl3NaZidWIOdg//smaIlP9ZMBDkHZGFd9ubphUZP9pUyDEo7bC6M0IIZR51o75qQw== + dependencies: + "@jest/expect-utils" "^29.0.2" + jest-get-type "^29.0.0" + jest-matcher-utils "^29.0.2" + jest-message-util "^29.0.2" + jest-util "^29.0.2" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +follow-redirects@^1.14.0: + version "1.15.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +from@~0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-core-module@^2.9.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" + integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== + dependencies: + has "^1.0.3" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz#31d18bdd127f825dd02ea7bfdfd906f8ab840e9f" + integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-28.1.3.tgz#d9aeee6792be3686c47cb988a8eaf82ff4238831" + integrity sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-circus@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.3.tgz#d14bd11cf8ee1a03d69902dc47b6bd4634ee00e4" + integrity sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/expect" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-runtime "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + p-limit "^3.1.0" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.3.tgz#558b33c577d06de55087b8448d373b9f654e46b2" + integrity sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ== + dependencies: + "@jest/core" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-config@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.3.tgz#e315e1f73df3cac31447eed8b8740a477392ec60" + integrity sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^28.1.3" + "@jest/types" "^28.1.3" + babel-jest "^28.1.3" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^28.1.3" + jest-environment-node "^28.1.3" + jest-get-type "^28.0.2" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-runner "^28.1.3" + jest-util "^28.1.3" + jest-validate "^28.1.3" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^28.1.3" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.3.tgz#948a192d86f4e7a64c5264ad4da4877133d8792f" + integrity sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw== + dependencies: + chalk "^4.0.0" + diff-sequences "^28.1.1" + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-diff@^29.0.2: + version "29.0.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.0.2.tgz#1a99419efda66f9ee72f91e580e774df95de5ddc" + integrity sha512-b9l9970sa1rMXH1owp2Woprmy42qIwwll/htsw4Gf7+WuSp5bZxNhkKHDuCGKL+HoHn1KhcC+tNEeAPYBkD2Jg== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.0.0" + jest-get-type "^29.0.0" + pretty-format "^29.0.2" + +jest-docblock@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8" + integrity sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA== + dependencies: + detect-newline "^3.0.0" + +jest-each@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-28.1.3.tgz#bdd1516edbe2b1f3569cfdad9acd543040028f81" + integrity sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g== + dependencies: + "@jest/types" "^28.1.3" + chalk "^4.0.0" + jest-get-type "^28.0.2" + jest-util "^28.1.3" + pretty-format "^28.1.3" + +jest-environment-node@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.3.tgz#7e74fe40eb645b9d56c0c4b70ca4357faa349be5" + integrity sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + jest-mock "^28.1.3" + jest-util "^28.1.3" + +jest-get-type@^28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" + integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== + +jest-get-type@^29.0.0: + version "29.0.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.0.0.tgz#843f6c50a1b778f7325df1129a0fd7aa713aef80" + integrity sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw== + +jest-haste-map@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-28.1.3.tgz#abd5451129a38d9841049644f34b034308944e2b" + integrity sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA== + dependencies: + "@jest/types" "^28.1.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^28.0.2" + jest-util "^28.1.3" + jest-worker "^28.1.3" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz#a6685d9b074be99e3adee816ce84fd30795e654d" + integrity sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA== + dependencies: + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-matcher-utils@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz#5a77f1c129dd5ba3b4d7fc20728806c78893146e" + integrity sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw== + dependencies: + chalk "^4.0.0" + jest-diff "^28.1.3" + jest-get-type "^28.0.2" + pretty-format "^28.1.3" + +jest-matcher-utils@^29.0.2: + version "29.0.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.0.2.tgz#0ffdcaec340a9810caee6c73ff90fb029b446e10" + integrity sha512-s62YkHFBfAx0JLA2QX1BlnCRFwHRobwAv2KP1+YhjzF6ZCbCVrf1sG8UJyn62ZUsDaQKpoo86XMTjkUyO5aWmQ== + dependencies: + chalk "^4.0.0" + jest-diff "^29.0.2" + jest-get-type "^29.0.0" + pretty-format "^29.0.2" + +jest-message-util@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.3.tgz#232def7f2e333f1eecc90649b5b94b0055e7c43d" + integrity sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^28.1.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^28.1.3" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-message-util@^29.0.2: + version "29.0.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.0.2.tgz#b2781dfb6a2d1c63830d9684c5148ae3155c6154" + integrity sha512-kcJAgms3ckJV0wUoLsAM40xAhY+pb9FVSZwicjFU9PFkaTNmqh9xd99/CzKse48wPM1ANUQKmp03/DpkY+lGrA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.0.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.0.2" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-28.1.3.tgz#d4e9b1fc838bea595c77ab73672ebf513ab249da" + integrity sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" + integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== + +jest-resolve-dependencies@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz#8c65d7583460df7275c6ea2791901fa975c1fe66" + integrity sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA== + dependencies: + jest-regex-util "^28.0.2" + jest-snapshot "^28.1.3" + +jest-resolve@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-28.1.3.tgz#cfb36100341ddbb061ec781426b3c31eb51aa0a8" + integrity sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-pnp-resolver "^1.2.2" + jest-util "^28.1.3" + jest-validate "^28.1.3" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.3.tgz#5eee25febd730b4713a2cdfd76bdd5557840f9a1" + integrity sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA== + dependencies: + "@jest/console" "^28.1.3" + "@jest/environment" "^28.1.3" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.10.2" + graceful-fs "^4.2.9" + jest-docblock "^28.1.1" + jest-environment-node "^28.1.3" + jest-haste-map "^28.1.3" + jest-leak-detector "^28.1.3" + jest-message-util "^28.1.3" + jest-resolve "^28.1.3" + jest-runtime "^28.1.3" + jest-util "^28.1.3" + jest-watcher "^28.1.3" + jest-worker "^28.1.3" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.3.tgz#a57643458235aa53e8ec7821949e728960d0605f" + integrity sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw== + dependencies: + "@jest/environment" "^28.1.3" + "@jest/fake-timers" "^28.1.3" + "@jest/globals" "^28.1.3" + "@jest/source-map" "^28.1.2" + "@jest/test-result" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^28.1.3" + jest-message-util "^28.1.3" + jest-mock "^28.1.3" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.3" + jest-snapshot "^28.1.3" + jest-util "^28.1.3" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.3.tgz#17467b3ab8ddb81e2f605db05583d69388fc0668" + integrity sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^28.1.3" + "@jest/transform" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^28.1.3" + graceful-fs "^4.2.9" + jest-diff "^28.1.3" + jest-get-type "^28.0.2" + jest-haste-map "^28.1.3" + jest-matcher-utils "^28.1.3" + jest-message-util "^28.1.3" + jest-util "^28.1.3" + natural-compare "^1.4.0" + pretty-format "^28.1.3" + semver "^7.3.5" + +jest-util@^28.0.0, jest-util@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.3.tgz#f4f932aa0074f0679943220ff9cbba7e497028b0" + integrity sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ== + dependencies: + "@jest/types" "^28.1.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-util@^29.0.2: + version "29.0.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.0.2.tgz#c75c5cab7f3b410782f9570a60c5558b5dfb6e3a" + integrity sha512-ozk8ruEEEACxqpz0hN9UOgtPZS0aN+NffwQduR5dVlhN+eN47vxurtvgZkYZYMpYrsmlAEx1XabkB3BnN0GfKQ== + dependencies: + "@jest/types" "^29.0.2" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-28.1.3.tgz#e322267fd5e7c64cea4629612c357bbda96229df" + integrity sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA== + dependencies: + "@jest/types" "^28.1.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^28.0.2" + leven "^3.1.0" + pretty-format "^28.1.3" + +jest-watcher@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.3.tgz#c6023a59ba2255e3b4c57179fc94164b3e73abd4" + integrity sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g== + dependencies: + "@jest/test-result" "^28.1.3" + "@jest/types" "^28.1.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.10.2" + jest-util "^28.1.3" + string-length "^4.0.1" + +jest-worker@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.3.tgz#7e3c4ce3fa23d1bb6accb169e7f396f98ed4bb98" + integrity sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^28.0.2: + version "28.1.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.3.tgz#e9c6a7eecdebe3548ca2b18894a50f45b36dfc6b" + integrity sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA== + dependencies: + "@jest/core" "^28.1.3" + "@jest/types" "^28.1.3" + import-local "^3.0.2" + jest-cli "^28.1.3" + +joi@^17.4.0: + version "17.6.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.6.0.tgz#0bb54f2f006c09a96e75ce687957bd04290054b2" + integrity sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +lazy-ass@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" + integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-error@1.x, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.5, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-fetch@2: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + integrity sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A== + dependencies: + through "~2.3" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +prettier@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + +pretty-format@^28.1.3: + version "28.1.3" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5" + integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q== + dependencies: + "@jest/schemas" "^28.1.3" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +pretty-format@^29.0.0, pretty-format@^29.0.2: + version "29.0.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.0.2.tgz#7f7666a7bf05ba2bcacde61be81c6db64f6f3be6" + integrity sha512-wp3CdtUa3cSJVFn3Miu5a1+pxc1iPIQTenOAn+x5erXeN1+ryTcLesV5pbK/rlW5EKwp27x38MoYfNGaNXDDhg== + dependencies: + "@jest/schemas" "^29.0.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +ps-tree@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" + integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== + dependencies: + event-stream "=3.3.4" + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + +resolve@^1.20.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rxjs@^7.1.0: + version "7.5.6" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc" + integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw== + dependencies: + tslib "^2.1.0" + +safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +semver@7.x, semver@^7.3.5: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + integrity sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA== + dependencies: + through "2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + +start-server-and-test@^1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/start-server-and-test/-/start-server-and-test-1.14.0.tgz#c57f04f73eac15dd51733b551d775b40837fdde3" + integrity sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw== + dependencies: + bluebird "3.7.2" + check-more-types "2.24.0" + debug "4.3.2" + execa "5.1.1" + lazy-ass "1.6.0" + ps-tree "1.2.0" + wait-on "6.0.0" + +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + integrity sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw== + dependencies: + duplexer "~0.1.1" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +through@2, through@~2.3, through@~2.3.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +timekeeper@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/timekeeper/-/timekeeper-2.2.0.tgz#9645731fce9e3280a18614a57a9d1b72af3ca368" + integrity sha512-W3AmPTJWZkRwu+iSNxPIsLZ2ByADsOLbbLxe46UJyWj3mlYLlwucKiq+/dPm0l9wTzqoF3/2PH0AGFCebjq23A== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +ts-jest@28.0.8: + version "28.0.8" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.8.tgz#cd204b8e7a2f78da32cf6c95c9a6165c5b99cc73" + integrity sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^28.0.0" + json5 "^2.2.1" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "^21.0.1" + +ts-node@^10.9.1: + version "10.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tsconfig-paths@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.1.0.tgz#f8ef7d467f08ae3a695335bf1ece088c5538d2c1" + integrity sha512-AHx4Euop/dXFC+Vx589alFba8QItjF+8hf8LtmuiCwHyI4rHXQtOOENaM8kvYf5fR0dRChy3wzWIZ9WbB7FWow== + dependencies: + json5 "^2.2.1" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typescript@^4.8.2: + version "4.8.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790" + integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw== + +update-browserslist-db@^1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.7.tgz#16279639cff1d0f800b14792de43d97df2d11b7d" + integrity sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-to-istanbul@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" + integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + +wait-on@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-6.0.0.tgz#7e9bf8e3d7fe2daecbb7a570ac8ca41e9311c7e7" + integrity sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw== + dependencies: + axios "^0.21.1" + joi "^17.4.0" + lodash "^4.17.21" + minimist "^1.2.5" + rxjs "^7.1.0" + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.0.0, yargs-parser@^21.0.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.5.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" + integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From 10387a306197ac854a6ccc5a831559e022d15766 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Tue, 6 Sep 2022 09:08:49 +0100 Subject: [PATCH 2/8] make sure yarn gets run in qa-core --- .github/workflows/budibase_ci.yml | 5 ++++- package.json | 2 -- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index df7a36caa4..23cdfba236 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -60,4 +60,7 @@ jobs: # install: false # command: yarn test:e2e:ci - - run: yarn test:api:ci \ No newline at end of file + - run: | + cd qa-core + yarn + yarn api:test:ci \ No newline at end of file diff --git a/package.json b/package.json index a2d8f28f43..4c24e0025b 100644 --- a/package.json +++ b/package.json @@ -52,8 +52,6 @@ "test:e2e:ci": "lerna run cy:ci --stream", "test:e2e:ci:record": "lerna run cy:ci:record --stream", "test:e2e:ci:notify": "lerna run cy:ci:notify", - "test:api:ci": "npm --prefix ./qa-core run api:test:ci", - "test:api": "npm --prefix ./qa-core run api:test", "build:specs": "lerna run specs", "build:docker": "lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh $BUDIBASE_RELEASE_VERSION && cd -", "build:docker:pre": "lerna run build && lerna run predocker", From 3c0b9344d80f34e6df22c8c7a63f4dacfad6351c Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 15 Sep 2022 00:58:08 +0100 Subject: [PATCH 3/8] complete refactor and total type safety of test suite - making use of OpenAPI types throughout --- package.json | 4 +- .../api/controllers/public/mapping/types.ts | 8 ++ .../server/src/api/routes/tests/user.spec.js | 1 + qa-core/package.json | 24 +++-- qa-core/scripts/jestSetup.js | 6 +- .../TestConfiguration}/PublicAPIClient.ts | 26 ++--- .../TestConfiguration/applications.ts | 49 ++++++++++ .../TestConfiguration}/generator.ts | 2 +- .../public-api/TestConfiguration/index.ts | 27 ++++++ .../public-api/TestConfiguration/rows.ts | 58 ++++++++++++ .../public-api/TestConfiguration/tables.ts | 62 ++++++++++++ .../public-api/TestConfiguration/users.ts | 41 ++++++++ .../public-api/fixtures/applications.ts | 10 ++ .../src/config/public-api/fixtures/tables.ts | 56 +++++++++++ .../src/config/public-api/fixtures/users.ts | 22 +++++ qa-core/src/environment.ts | 6 +- qa-core/src/jest.extends.ts | 11 ++- .../src/tests/public-api/TestConfiguration.ts | 39 -------- .../applications/applications.spec.ts | 39 ++++---- .../applications/fixtures/application.json | 4 - .../applications/fixtures/generate.ts | 9 -- .../applications/fixtures/seed.json | 4 - .../fixtures/update_application.json | 4 - .../tests/public-api/tables/fixtures/row.json | 8 -- .../public-api/tables/fixtures/seed.json | 94 ------------------- .../public-api/tables/fixtures/table.json | 94 ------------------- .../tables/fixtures/update_row.json | 8 -- .../tables/fixtures/update_table.json | 94 ------------------- .../src/tests/public-api/tables/rows.spec.ts | 43 ++++----- .../tests/public-api/tables/tables.spec.ts | 38 ++++---- .../public-api/users/fixtures/generate.ts | 22 ----- .../users/fixtures/update_user.json | 18 ---- .../tests/public-api/users/fixtures/user.json | 18 ---- .../src/tests/public-api/users/users.spec.ts | 32 +++---- qa-core/tsconfig.json | 3 - qa-core/yarn.lock | 43 +++++---- 36 files changed, 470 insertions(+), 557 deletions(-) rename qa-core/src/{tests/public-api => config/public-api/TestConfiguration}/PublicAPIClient.ts (74%) create mode 100644 qa-core/src/config/public-api/TestConfiguration/applications.ts rename qa-core/src/{tests/public-api => config/public-api/TestConfiguration}/generator.ts (54%) create mode 100644 qa-core/src/config/public-api/TestConfiguration/index.ts create mode 100644 qa-core/src/config/public-api/TestConfiguration/rows.ts create mode 100644 qa-core/src/config/public-api/TestConfiguration/tables.ts create mode 100644 qa-core/src/config/public-api/TestConfiguration/users.ts create mode 100644 qa-core/src/config/public-api/fixtures/applications.ts create mode 100644 qa-core/src/config/public-api/fixtures/tables.ts create mode 100644 qa-core/src/config/public-api/fixtures/users.ts delete mode 100644 qa-core/src/tests/public-api/TestConfiguration.ts delete mode 100644 qa-core/src/tests/public-api/applications/fixtures/application.json delete mode 100644 qa-core/src/tests/public-api/applications/fixtures/generate.ts delete mode 100644 qa-core/src/tests/public-api/applications/fixtures/seed.json delete mode 100644 qa-core/src/tests/public-api/applications/fixtures/update_application.json delete mode 100644 qa-core/src/tests/public-api/tables/fixtures/row.json delete mode 100644 qa-core/src/tests/public-api/tables/fixtures/seed.json delete mode 100644 qa-core/src/tests/public-api/tables/fixtures/table.json delete mode 100644 qa-core/src/tests/public-api/tables/fixtures/update_row.json delete mode 100644 qa-core/src/tests/public-api/tables/fixtures/update_table.json delete mode 100644 qa-core/src/tests/public-api/users/fixtures/generate.ts delete mode 100644 qa-core/src/tests/public-api/users/fixtures/update_user.json delete mode 100644 qa-core/src/tests/public-api/users/fixtures/user.json diff --git a/package.json b/package.json index 4c24e0025b..71acd886d3 100644 --- a/package.json +++ b/package.json @@ -45,8 +45,8 @@ "lint:eslint": "eslint packages", "lint:prettier": "prettier --check \"packages/**/*.{js,ts,svelte}\"", "lint": "yarn run lint:eslint && yarn run lint:prettier", - "lint:fix:eslint": "eslint --fix packages", - "lint:fix:prettier": "prettier --write \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\"", + "lint:fix:eslint": "eslint --fix packages qa-core", + "lint:fix:prettier": "prettier --write \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\" && prettier --write \"qa-core/**/*.{js,ts,svelte}\"", "lint:fix": "yarn run lint:fix:prettier && yarn run lint:fix:eslint", "test:e2e": "lerna run cy:test --stream", "test:e2e:ci": "lerna run cy:ci --stream", diff --git a/packages/server/src/api/controllers/public/mapping/types.ts b/packages/server/src/api/controllers/public/mapping/types.ts index a82a525f9c..5d161ec17a 100644 --- a/packages/server/src/api/controllers/public/mapping/types.ts +++ b/packages/server/src/api/controllers/public/mapping/types.ts @@ -4,10 +4,18 @@ export type Query = components["schemas"]["query"] export type ExecuteQuery = components["schemas"]["executeQueryOutput"] export type Application = components["schemas"]["applicationOutput"]["data"] +export type CreateApplicationParams = components["schemas"]["application"] export type Table = components["schemas"]["tableOutput"]["data"] +export type CreateTableParams = components["schemas"]["table"] export type Row = components["schemas"]["rowOutput"]["data"] export type RowSearch = components["schemas"]["searchOutput"] +export type CreateRowParams = components["schemas"]["row"] export type User = components["schemas"]["userOutput"]["data"] +export type CreateUserParams = components["schemas"]["user"] + +export type SearchInputParams = + | components["schemas"]["nameSearch"] + | components["schemas"]["querySearch"] diff --git a/packages/server/src/api/routes/tests/user.spec.js b/packages/server/src/api/routes/tests/user.spec.js index a7f1e7e7dc..e699f818d6 100644 --- a/packages/server/src/api/routes/tests/user.spec.js +++ b/packages/server/src/api/routes/tests/user.spec.js @@ -23,6 +23,7 @@ describe("/users", () => { }) describe("fetch", () => { + it("returns a list of users from an instance db", async () => { await config.createUser("uuidx") await config.createUser("uuidy") diff --git a/qa-core/package.json b/qa-core/package.json index 30d2fc9526..2103f1670e 100644 --- a/qa-core/package.json +++ b/qa-core/package.json @@ -21,8 +21,6 @@ "preset": "ts-jest", "testEnvironment": "node", "moduleNameMapper": { - "@budibase/backend-core/(.*)": "/../packages/backend-core/$1", - "@budibase/backend-core": "/../packages/backend-core/src", "@budibase/types": "/../packages/types/src" }, "setupFiles": [ @@ -33,18 +31,18 @@ ] }, "devDependencies": { - "@budibase/types": "^1.3.4", - "@types/jest": "^29.0.0", - "@types/node-fetch": "^2.6.2", - "chance": "^1.1.8", - "jest": "^28.0.2", - "prettier": "^2.7.1", - "start-server-and-test": "^1.14.0", - "timekeeper": "^2.2.0", + "@budibase/types": "1.3.4", + "@types/jest": "29.0.0", + "@types/node-fetch": "2.6.2", + "chance": "1.1.8", + "jest": "28.0.2", + "prettier": "2.7.1", + "start-server-and-test": "1.14.0", + "timekeeper": "2.2.0", "ts-jest": "28.0.8", - "ts-node": "^10.9.1", - "tsconfig-paths": "^4.1.0", - "typescript": "^4.8.2" + "ts-node": "10.9.1", + "tsconfig-paths": "4.1.0", + "typescript": "4.7.3" }, "dependencies": { "node-fetch": "2" diff --git a/qa-core/scripts/jestSetup.js b/qa-core/scripts/jestSetup.js index 5902a68af7..8254fd6d34 100644 --- a/qa-core/scripts/jestSetup.js +++ b/qa-core/scripts/jestSetup.js @@ -1,12 +1,14 @@ const env = require("../src/environment") env._set("BUDIBASE_SERVER_URL", "http://localhost:4100") -env._set("BUDIBASE_PUBLIC_API_KEY", "a65722f06bee5caeadc5d7ca2f543a43-d610e627344210c643bb726f") +env._set( + "BUDIBASE_PUBLIC_API_KEY", + "a65722f06bee5caeadc5d7ca2f543a43-d610e627344210c643bb726f" +) // mock all dates to 2020-01-01T00:00:00.000Z // use tk.reset() to use real dates in individual tests const MOCK_DATE = new Date("2020-01-01T00:00:00.000Z") -const MOCK_DATE_TIMESTAMP = 1577836800000 const tk = require("timekeeper") tk.freeze(MOCK_DATE) diff --git a/qa-core/src/tests/public-api/PublicAPIClient.ts b/qa-core/src/config/public-api/TestConfiguration/PublicAPIClient.ts similarity index 74% rename from qa-core/src/tests/public-api/PublicAPIClient.ts rename to qa-core/src/config/public-api/TestConfiguration/PublicAPIClient.ts index 017d8088dd..405007b5aa 100644 --- a/qa-core/src/tests/public-api/PublicAPIClient.ts +++ b/qa-core/src/config/public-api/TestConfiguration/PublicAPIClient.ts @@ -1,14 +1,14 @@ -import env from "../../environment" -import fetch from "node-fetch" - -interface HeaderOptions { - headers?: object; - body?: object; - json?: boolean; -} +import env from "../../../environment" +import fetch, { HeadersInit } from "node-fetch" type APIMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" +interface ApiOptions { + method?: APIMethod + body?: object + headers?: HeadersInit | undefined +} + class PublicAPIClient { host: string apiKey: string @@ -16,7 +16,9 @@ class PublicAPIClient { constructor(appId?: string) { if (!env.BUDIBASE_PUBLIC_API_KEY || !env.BUDIBASE_SERVER_URL) { - throw new Error("Must set BUDIBASE_PUBLIC_API_KEY and BUDIBASE_SERVER_URL env vars") + throw new Error( + "Must set BUDIBASE_PUBLIC_API_KEY and BUDIBASE_SERVER_URL env vars" + ) } this.host = `${env.BUDIBASE_SERVER_URL}/api/public/v1` this.apiKey = env.BUDIBASE_PUBLIC_API_KEY @@ -25,9 +27,9 @@ class PublicAPIClient { apiCall = (method: APIMethod) => - async (url = "", options: HeaderOptions = {}) => { + async (url = "", options: ApiOptions = {}) => { const requestOptions = { - method: method, + method, body: JSON.stringify(options.body), headers: { "x-budibase-api-key": this.apiKey, @@ -55,4 +57,4 @@ class PublicAPIClient { put = this.apiCall("PUT") } -export default PublicAPIClient \ No newline at end of file +export default PublicAPIClient diff --git a/qa-core/src/config/public-api/TestConfiguration/applications.ts b/qa-core/src/config/public-api/TestConfiguration/applications.ts new file mode 100644 index 0000000000..6232c14c28 --- /dev/null +++ b/qa-core/src/config/public-api/TestConfiguration/applications.ts @@ -0,0 +1,49 @@ +import PublicAPIClient from "./PublicAPIClient" +import { + Application, + SearchInputParams, + CreateApplicationParams, +} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { Response } from "node-fetch" +import generateApp from "../fixtures/applications" + +export default class AppApi { + api: PublicAPIClient + + constructor(apiClient: PublicAPIClient) { + this.api = apiClient + } + + async seed(): Promise<[Response, Application]> { + return this.create(generateApp()) + } + + async create( + body: CreateApplicationParams + ): Promise<[Response, Application]> { + const response = await this.api.post(`/applications`, { body }) + const json = await response.json() + return [response, json.data] + } + + async read(id: string): Promise<[Response, Application]> { + const response = await this.api.get(`/applications/${id}`) + const json = await response.json() + return [response, json.data] + } + + async search(body: SearchInputParams): Promise<[Response, Application]> { + const response = await this.api.post(`/applications/search`, { body }) + const json = await response.json() + return [response, json.data] + } + + async update( + id: string, + body: Application + ): Promise<[Response, Application]> { + const response = await this.api.put(`/applications/${id}`, { body }) + const json = await response.json() + return [response, json.data] + } +} diff --git a/qa-core/src/tests/public-api/generator.ts b/qa-core/src/config/public-api/TestConfiguration/generator.ts similarity index 54% rename from qa-core/src/tests/public-api/generator.ts rename to qa-core/src/config/public-api/TestConfiguration/generator.ts index f9ef06f243..c9395f7e47 100644 --- a/qa-core/src/tests/public-api/generator.ts +++ b/qa-core/src/config/public-api/TestConfiguration/generator.ts @@ -1,3 +1,3 @@ const Chance = require("chance") -export default new Chance() \ No newline at end of file +export default new Chance() diff --git a/qa-core/src/config/public-api/TestConfiguration/index.ts b/qa-core/src/config/public-api/TestConfiguration/index.ts new file mode 100644 index 0000000000..36cc3022b0 --- /dev/null +++ b/qa-core/src/config/public-api/TestConfiguration/index.ts @@ -0,0 +1,27 @@ +import PublicAPIClient from "./PublicAPIClient" +import ApplicationApi from "./applications" +import TableApi from "./tables" +import UserApi from "./users" +import RowApi from "./rows" + +export default class TestConfiguration { + applications: ApplicationApi + users: UserApi + tables: TableApi + rows: RowApi + context: T + + constructor(apiClient: PublicAPIClient) { + this.applications = new ApplicationApi(apiClient) + this.users = new UserApi(apiClient) + this.tables = new TableApi(apiClient) + this.rows = new RowApi(apiClient) + this.context = {} + } + + async beforeAll() {} + + async afterAll() { + this.context = {} + } +} diff --git a/qa-core/src/config/public-api/TestConfiguration/rows.ts b/qa-core/src/config/public-api/TestConfiguration/rows.ts new file mode 100644 index 0000000000..4e39e4ec9e --- /dev/null +++ b/qa-core/src/config/public-api/TestConfiguration/rows.ts @@ -0,0 +1,58 @@ +import PublicAPIClient from "./PublicAPIClient" +import { + CreateRowParams, + Row, + SearchInputParams, +} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { HeadersInit, Response } from "node-fetch" + +export default class RowApi { + api: PublicAPIClient + headers?: HeadersInit + tableId?: string + + constructor(apiClient: PublicAPIClient) { + this.api = apiClient + } + + set appId(appId: string) { + this.headers = { + "x-budibase-app-id": appId, + } + } + + async create(body: CreateRowParams): Promise<[Response, Row]> { + const response = await this.api.post(`/tables/${this.tableId}/rows`, { + body, + headers: this.headers, + }) + const json = await response.json() + return [response, json.data] + } + + async read(id: string): Promise<[Response, Row]> { + const response = await this.api.get(`/tables/${this.tableId}/rows/${id}`, { + headers: this.headers, + }) + const json = await response.json() + return [response, json.data] + } + + async search(body: SearchInputParams): Promise<[Response, Row]> { + const response = await this.api.post( + `/tables/${this.tableId}/rows/search`, + { body, headers: this.headers } + ) + const json = await response.json() + return [response, json.data] + } + + async update(id: string, body: Row): Promise<[Response, Row]> { + const response = await this.api.put(`/tables/${this.tableId}/rows/${id}`, { + body, + headers: this.headers, + }) + const json = await response.json() + return [response, json.data] + } +} diff --git a/qa-core/src/config/public-api/TestConfiguration/tables.ts b/qa-core/src/config/public-api/TestConfiguration/tables.ts new file mode 100644 index 0000000000..c0b7e088e1 --- /dev/null +++ b/qa-core/src/config/public-api/TestConfiguration/tables.ts @@ -0,0 +1,62 @@ +import PublicAPIClient from "./PublicAPIClient" +import { + Table, + SearchInputParams, + CreateTableParams, +} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { HeadersInit, Response } from "node-fetch" +import { generateTable } from "../fixtures/tables" + +export default class TableApi { + api: PublicAPIClient + headers?: HeadersInit + + constructor(apiClient: PublicAPIClient) { + this.api = apiClient + } + + async seed() { + return this.create(generateTable()) + } + + set appId(appId: string) { + this.headers = { + "x-budibase-app-id": appId, + } + } + + async create(body: CreateTableParams): Promise<[Response, Table]> { + const response = await this.api.post(`/tables`, { + body, + headers: this.headers, + }) + const json = await response.json() + return [response, json.data] + } + + async read(id: string): Promise<[Response, Table]> { + const response = await this.api.get(`/tables/${id}`, { + headers: this.headers, + }) + const json = await response.json() + return [response, json.data] + } + + async search(body: SearchInputParams): Promise<[Response, Table]> { + const response = await this.api.post(`/tables/search`, { + body, + headers: this.headers, + }) + const json = await response.json() + return [response, json.data] + } + + async update(id: string, body: Table): Promise<[Response, Table]> { + const response = await this.api.put(`/tables/${id}`, { + body, + headers: this.headers, + }) + const json = await response.json() + return [response, json.data] + } +} diff --git a/qa-core/src/config/public-api/TestConfiguration/users.ts b/qa-core/src/config/public-api/TestConfiguration/users.ts new file mode 100644 index 0000000000..79217620aa --- /dev/null +++ b/qa-core/src/config/public-api/TestConfiguration/users.ts @@ -0,0 +1,41 @@ +import PublicAPIClient from "./PublicAPIClient" +import { + CreateUserParams, + SearchInputParams, + User, +} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { Response } from "node-fetch" + +export default class UserApi { + api: PublicAPIClient + + constructor(apiClient: PublicAPIClient) { + this.api = apiClient + } + + async seed() {} + + async create(body: CreateUserParams): Promise<[Response, User]> { + const response = await this.api.post(`/users`, { body }) + const json = await response.json() + return [response, json.data] + } + + async read(id: string): Promise<[Response, User]> { + const response = await this.api.get(`/users/${id}`) + const json = await response.json() + return [response, json.data] + } + + async search(body: SearchInputParams): Promise<[Response, User]> { + const response = await this.api.post(`/users/search`, { body }) + const json = await response.json() + return [response, json.data] + } + + async update(id: string, body: User): Promise<[Response, User]> { + const response = await this.api.put(`/users/${id}`, { body }) + const json = await response.json() + return [response, json.data] + } +} diff --git a/qa-core/src/config/public-api/fixtures/applications.ts b/qa-core/src/config/public-api/fixtures/applications.ts new file mode 100644 index 0000000000..25456f4c4b --- /dev/null +++ b/qa-core/src/config/public-api/fixtures/applications.ts @@ -0,0 +1,10 @@ +import generator from "../TestConfiguration/generator" +import { CreateApplicationParams } from "../../../../../packages/server/src/api/controllers/public/mapping/types" + +const generate = (overrides = {}): CreateApplicationParams => ({ + name: generator.word(), + url: `/${generator.word()}`, + ...overrides, +}) + +export default generate diff --git a/qa-core/src/config/public-api/fixtures/tables.ts b/qa-core/src/config/public-api/fixtures/tables.ts new file mode 100644 index 0000000000..bbf93322c3 --- /dev/null +++ b/qa-core/src/config/public-api/fixtures/tables.ts @@ -0,0 +1,56 @@ +import { + CreateRowParams, + CreateTableParams, +} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import generator from "../TestConfiguration/generator" + +export const generateTable = (overrides = {}): CreateTableParams => ({ + name: generator.word(), + primaryDisplay: "sasa", + schema: { + "Auto ID": { + autocolumn: true, + name: "Auto ID", + type: "number", + }, + "Created At": { + autocolumn: true, + name: "Created At", + type: "datetime", + }, + "Created By": { + autocolumn: true, + fieldName: "test12-Created By", + name: "Created By", + relationshipType: "many-to-many", + tableId: "ta_users", + type: "link", + }, + sasa: { + name: "sasa", + type: "string", + }, + "Updated At": { + autocolumn: true, + name: "Updated At", + type: "datetime", + }, + "Updated By": { + autocolumn: true, + fieldName: "test12-Updated By", + name: "Updated By", + relationshipType: "many-to-many", + tableId: "ta_users", + type: "link", + }, + }, + ...overrides, +}) + +export const generateRow = (overrides = {}): CreateRowParams => ({ + type: "row", + tableId: "seed_table", + sasa: "Mike", + relationship: ["ro_ta_"], + ...overrides, +}) diff --git a/qa-core/src/config/public-api/fixtures/users.ts b/qa-core/src/config/public-api/fixtures/users.ts new file mode 100644 index 0000000000..52124024e7 --- /dev/null +++ b/qa-core/src/config/public-api/fixtures/users.ts @@ -0,0 +1,22 @@ +import { CreateUserParams } from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import generator from "../TestConfiguration/generator" + +const generate = (overrides = {}): CreateUserParams => ({ + email: generator.email(), + roles: { + [generator.string({ length: 32, alpha: true, numeric: true })]: + generator.word(), + }, + password: generator.word(), + status: "active", + forceResetPassword: generator.bool(), + builder: { + global: generator.bool(), + }, + admin: { + global: generator.bool(), + }, + ...overrides, +}) + +export default generate diff --git a/qa-core/src/environment.ts b/qa-core/src/environment.ts index 4ef8de795a..b0ed3cec85 100644 --- a/qa-core/src/environment.ts +++ b/qa-core/src/environment.ts @@ -1,8 +1,10 @@ -export = { +const env = { BUDIBASE_SERVER_URL: process.env.BUDIBASE_SERVER_URL, BUDIBASE_PUBLIC_API_KEY: process.env.BUDIBASE_PUBLIC_API_KEY, _set(key: any, value: any) { process.env[key] = value module.exports[key] = value }, -} \ No newline at end of file +} + +export = env diff --git a/qa-core/src/jest.extends.ts b/qa-core/src/jest.extends.ts index 380bf85c81..653009f5f0 100644 --- a/qa-core/src/jest.extends.ts +++ b/qa-core/src/jest.extends.ts @@ -1,21 +1,22 @@ +import { Response } from "node-fetch" + // boilerplate to allow TS updates to the global scope -export {}; +export {} declare global { namespace jest { interface Matchers { - toHaveStatusCode(code: number): R; + toHaveStatusCode(code: number): R } } } // Expect extensions expect.extend({ - toHaveStatusCode(received, code) { + toHaveStatusCode(received: Response, code: number) { const pass = received.status === code return { - message: () => - `expected ${received.status} to match status code ${code}`, + message: () => `expected ${received.status} to match status code ${code}`, pass, } }, diff --git a/qa-core/src/tests/public-api/TestConfiguration.ts b/qa-core/src/tests/public-api/TestConfiguration.ts deleted file mode 100644 index 647e64758e..0000000000 --- a/qa-core/src/tests/public-api/TestConfiguration.ts +++ /dev/null @@ -1,39 +0,0 @@ -import PublicAPIClient from "./PublicAPIClient"; -import generateApp from "./applications/fixtures/generate" - -class TestConfiguration { - testContext: Record; - apiClient: PublicAPIClient; - - constructor() { - this.testContext = {} - this.apiClient = new PublicAPIClient() - } - - async beforeAll() { - - } - - async afterAll() { - } - - async seedTable(appId: string) { - const response = await this.apiClient.post("/tables", { - body: require("./tables/fixtures/seed.json"), - headers: { - "x-budibase-app-id": appId - } - }) - const json = await response.json() - return json.data - } - - async seedApp() { - const response = await this.apiClient.post("/applications", { - body: generateApp() - }) - return response.json() - } -} - -export default TestConfiguration diff --git a/qa-core/src/tests/public-api/applications/applications.spec.ts b/qa-core/src/tests/public-api/applications/applications.spec.ts index 83180429e0..1031f511b4 100644 --- a/qa-core/src/tests/public-api/applications/applications.spec.ts +++ b/qa-core/src/tests/public-api/applications/applications.spec.ts @@ -1,10 +1,11 @@ -import TestConfiguration from "../TestConfiguration" -import PublicAPIClient from "../PublicAPIClient" -import generateApp from "./fixtures/generate" +import TestConfiguration from "../../../config/public-api/TestConfiguration" +import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" +import generateApp from "../../../config/public-api/fixtures/applications" +import { Application } from "../../../../../packages/server/src/api/controllers/public/mapping/types" describe("Public API - /applications endpoints", () => { const api = new PublicAPIClient() - const config = new TestConfiguration() + const config = new TestConfiguration(api) beforeAll(async () => { await config.beforeAll() @@ -14,34 +15,30 @@ describe("Public API - /applications endpoints", () => { await config.afterAll() }) - it("POST - Create a application", async () => { - const response = await api.post(`/applications`, { - body: generateApp() - }) - const json = await response.json() - config.testContext.application = json.data + it("POST - Create an application", async () => { + const [response, app] = await config.applications.create(generateApp()) + config.context = app expect(response).toHaveStatusCode(200) }) it("POST - Search applications", async () => { - const response = await api.post(`/applications/search`, { - body: { - name: config.testContext.application.name - } + const [response, app] = await config.applications.search({ + name: config.context.name, }) expect(response).toHaveStatusCode(200) }) - it("GET - Retrieve a application", async () => { - const response = await api.get(`/applications/${config.testContext.application._id}`) + it("GET - Retrieve an application", async () => { + const [response, app] = await config.applications.read(config.context._id) expect(response).toHaveStatusCode(200) }) - - it("PUT - update a application", async () => { - const response = await api.put(`/applications/${config.testContext.application._id}`, { - body: require("./fixtures/update_application.json") - }) + it("PUT - update an application", async () => { + config.context.name = "UpdatedName" + const [response, app] = await config.applications.update( + config.context._id, + config.context + ) expect(response).toHaveStatusCode(200) }) }) diff --git a/qa-core/src/tests/public-api/applications/fixtures/application.json b/qa-core/src/tests/public-api/applications/fixtures/application.json deleted file mode 100644 index 093edbcb0e..0000000000 --- a/qa-core/src/tests/public-api/applications/fixtures/application.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "TestApp", - "url": "/testapp" -} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/applications/fixtures/generate.ts b/qa-core/src/tests/public-api/applications/fixtures/generate.ts deleted file mode 100644 index 2e28f6fb06..0000000000 --- a/qa-core/src/tests/public-api/applications/fixtures/generate.ts +++ /dev/null @@ -1,9 +0,0 @@ -import generator from "../../generator" - -const generate = (overrides = {}) => ({ - name: generator.word(), - url: `/${generator.word()}`, - ...overrides -}) - -export default generate \ No newline at end of file diff --git a/qa-core/src/tests/public-api/applications/fixtures/seed.json b/qa-core/src/tests/public-api/applications/fixtures/seed.json deleted file mode 100644 index 7a5de02e82..0000000000 --- a/qa-core/src/tests/public-api/applications/fixtures/seed.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "SeedApp", - "url": "/seedapp" -} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/applications/fixtures/update_application.json b/qa-core/src/tests/public-api/applications/fixtures/update_application.json deleted file mode 100644 index ea3b3d0b31..0000000000 --- a/qa-core/src/tests/public-api/applications/fixtures/update_application.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "UpdatedTestApp", - "url": "/updatedtestapp" -} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/fixtures/row.json b/qa-core/src/tests/public-api/tables/fixtures/row.json deleted file mode 100644 index 9436576947..0000000000 --- a/qa-core/src/tests/public-api/tables/fixtures/row.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "row", - "tableId": "seed_table", - "sasa": "Mike", - "relationship": [ - "ro_ta_" - ] -} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/fixtures/seed.json b/qa-core/src/tests/public-api/tables/fixtures/seed.json deleted file mode 100644 index acbaeaff6c..0000000000 --- a/qa-core/src/tests/public-api/tables/fixtures/seed.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "name": "test", - "primaryDisplay": "sasa", - "schema": { - "Auto ID": { - "autocolumn": true, - "constraints": { - "numericality": { - "greaterThanOrEqualTo": "", - "lessThanOrEqualTo": "" - }, - "presence": false, - "type": "number" - }, - "icon": "ri-magic-line", - "name": "Auto ID", - "subtype": "autoID", - "type": "number" - }, - "Created At": { - "autocolumn": true, - "constraints": { - "datetime": { - "earliest": "", - "latest": "" - }, - "length": {}, - "presence": false, - "type": "string" - }, - "icon": "ri-magic-line", - "name": "Created At", - "subtype": "createdAt", - "type": "datetime" - }, - "Created By": { - "autocolumn": true, - "constraints": { - "presence": false, - "type": "array" - }, - "fieldName": "test12-Created By", - "icon": "ri-magic-line", - "name": "Created By", - "relationshipType": "many-to-many", - "subtype": "createdBy", - "tableId": "ta_users", - "type": "link" - }, - "sasa": { - "constraints": { - "length": { - "maximum": null - }, - "presence": { - "allowEmpty": false - }, - "type": "string" - }, - "name": "sasa", - "type": "string" - }, - "Updated At": { - "autocolumn": true, - "constraints": { - "datetime": { - "earliest": "", - "latest": "" - }, - "length": {}, - "presence": false, - "type": "string" - }, - "icon": "ri-magic-line", - "name": "Updated At", - "subtype": "updatedAt", - "type": "datetime" - }, - "Updated By": { - "autocolumn": true, - "constraints": { - "presence": false, - "type": "array" - }, - "fieldName": "test12-Updated By", - "icon": "ri-magic-line", - "name": "Updated By", - "relationshipType": "many-to-many", - "subtype": "updatedBy", - "tableId": "ta_users", - "type": "link" - } - } -} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/fixtures/table.json b/qa-core/src/tests/public-api/tables/fixtures/table.json deleted file mode 100644 index acbaeaff6c..0000000000 --- a/qa-core/src/tests/public-api/tables/fixtures/table.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "name": "test", - "primaryDisplay": "sasa", - "schema": { - "Auto ID": { - "autocolumn": true, - "constraints": { - "numericality": { - "greaterThanOrEqualTo": "", - "lessThanOrEqualTo": "" - }, - "presence": false, - "type": "number" - }, - "icon": "ri-magic-line", - "name": "Auto ID", - "subtype": "autoID", - "type": "number" - }, - "Created At": { - "autocolumn": true, - "constraints": { - "datetime": { - "earliest": "", - "latest": "" - }, - "length": {}, - "presence": false, - "type": "string" - }, - "icon": "ri-magic-line", - "name": "Created At", - "subtype": "createdAt", - "type": "datetime" - }, - "Created By": { - "autocolumn": true, - "constraints": { - "presence": false, - "type": "array" - }, - "fieldName": "test12-Created By", - "icon": "ri-magic-line", - "name": "Created By", - "relationshipType": "many-to-many", - "subtype": "createdBy", - "tableId": "ta_users", - "type": "link" - }, - "sasa": { - "constraints": { - "length": { - "maximum": null - }, - "presence": { - "allowEmpty": false - }, - "type": "string" - }, - "name": "sasa", - "type": "string" - }, - "Updated At": { - "autocolumn": true, - "constraints": { - "datetime": { - "earliest": "", - "latest": "" - }, - "length": {}, - "presence": false, - "type": "string" - }, - "icon": "ri-magic-line", - "name": "Updated At", - "subtype": "updatedAt", - "type": "datetime" - }, - "Updated By": { - "autocolumn": true, - "constraints": { - "presence": false, - "type": "array" - }, - "fieldName": "test12-Updated By", - "icon": "ri-magic-line", - "name": "Updated By", - "relationshipType": "many-to-many", - "subtype": "updatedBy", - "tableId": "ta_users", - "type": "link" - } - } -} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/fixtures/update_row.json b/qa-core/src/tests/public-api/tables/fixtures/update_row.json deleted file mode 100644 index 556e02f8bd..0000000000 --- a/qa-core/src/tests/public-api/tables/fixtures/update_row.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "type": "row", - "tableId": "seed_table", - "sasa": "MikeIsTheBest", - "relationship": [ - "ro_ta_..." - ] -} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/fixtures/update_table.json b/qa-core/src/tests/public-api/tables/fixtures/update_table.json deleted file mode 100644 index 64ca1147e8..0000000000 --- a/qa-core/src/tests/public-api/tables/fixtures/update_table.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "name": "test123", - "primaryDisplay": "sasa", - "schema": { - "Auto ID": { - "autocolumn": true, - "constraints": { - "numericality": { - "greaterThanOrEqualTo": "", - "lessThanOrEqualTo": "" - }, - "presence": false, - "type": "number" - }, - "icon": "ri-magic-line", - "name": "Auto ID", - "subtype": "autoID", - "type": "number" - }, - "Created At": { - "autocolumn": true, - "constraints": { - "datetime": { - "earliest": "", - "latest": "" - }, - "length": {}, - "presence": false, - "type": "string" - }, - "icon": "ri-magic-line", - "name": "Created At", - "subtype": "createdAt", - "type": "datetime" - }, - "Created By": { - "autocolumn": true, - "constraints": { - "presence": false, - "type": "array" - }, - "fieldName": "test12-Created By", - "icon": "ri-magic-line", - "name": "Created By", - "relationshipType": "many-to-many", - "subtype": "createdBy", - "tableId": "ta_users", - "type": "link" - }, - "sasa": { - "constraints": { - "length": { - "maximum": null - }, - "presence": { - "allowEmpty": false - }, - "type": "string" - }, - "name": "sasa", - "type": "string" - }, - "Updated At": { - "autocolumn": true, - "constraints": { - "datetime": { - "earliest": "", - "latest": "" - }, - "length": {}, - "presence": false, - "type": "string" - }, - "icon": "ri-magic-line", - "name": "Updated At", - "subtype": "updatedAt", - "type": "datetime" - }, - "Updated By": { - "autocolumn": true, - "constraints": { - "presence": false, - "type": "array" - }, - "fieldName": "test12-Updated By", - "icon": "ri-magic-line", - "name": "Updated By", - "relationshipType": "many-to-many", - "subtype": "updatedBy", - "tableId": "ta_users", - "type": "link" - } - } -} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/tables/rows.spec.ts b/qa-core/src/tests/public-api/tables/rows.spec.ts index 099a3d3593..66d46208cc 100644 --- a/qa-core/src/tests/public-api/tables/rows.spec.ts +++ b/qa-core/src/tests/public-api/tables/rows.spec.ts @@ -1,17 +1,22 @@ -import TestConfiguration from "../TestConfiguration" -import PublicAPIClient from "../PublicAPIClient" +import { Row } from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { generateRow } from "../../../config/public-api/fixtures/tables" +import TestConfiguration from "../../../config/public-api/TestConfiguration" +import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" describe("Public API - /rows endpoints", () => { - let api: PublicAPIClient + let api = new PublicAPIClient() - const config = new TestConfiguration() + const config = new TestConfiguration(api) beforeAll(async () => { await config.beforeAll() - const app = await config.seedApp() + const [appResp, app] = await config.applications.seed() - config.testContext.table = await config.seedTable(app.data._id) - api = new PublicAPIClient(app.data._id) + config.tables.appId = app._id + const [tableResp, table] = await config.tables.seed() + + config.rows.appId = app._id + config.rows.tableId = table._id }) afterAll(async () => { @@ -19,33 +24,29 @@ describe("Public API - /rows endpoints", () => { }) it("POST - Create a row", async () => { - const response = await api.post(`/tables/${config.testContext.table._id}/rows`, { - body: require("./fixtures/row.json") - }) - const json = await response.json() - config.testContext.row = json.data + const [response, row] = await config.rows.create(generateRow()) + config.context = row expect(response).toHaveStatusCode(200) }) it("POST - Search rows", async () => { - const response = await api.post(`/tables/${config.testContext.table._id}/rows/search`, { - body: { - name: config.testContext.row.name - } + const [response, row] = await config.rows.search({ + name: config.context.name as string, }) expect(response).toHaveStatusCode(200) }) it("GET - Retrieve a row", async () => { - const response = await api.get(`/tables/${config.testContext.table._id}/rows/${config.testContext.row._id}`) + const [response, row] = await config.rows.read(config.context._id) expect(response).toHaveStatusCode(200) }) - it("PUT - update a row", async () => { - const response = await api.put(`/tables/${config.testContext.table._id}/rows/${config.testContext.row._id}`, { - body: require("./fixtures/update_row.json") - }) + config.context.name = "UpdatedName" + const [response, row] = await config.rows.update( + config.context._id, + config.context + ) expect(response).toHaveStatusCode(200) }) }) diff --git a/qa-core/src/tests/public-api/tables/tables.spec.ts b/qa-core/src/tests/public-api/tables/tables.spec.ts index 70e3bb8d78..9dfdc8cdc0 100644 --- a/qa-core/src/tests/public-api/tables/tables.spec.ts +++ b/qa-core/src/tests/public-api/tables/tables.spec.ts @@ -1,14 +1,16 @@ -import TestConfiguration from "../TestConfiguration" -import PublicAPIClient from "../PublicAPIClient" +import { Table } from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { generateTable } from "../../../config/public-api/fixtures/tables" +import TestConfiguration from "../../../config/public-api/TestConfiguration" +import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" describe("Public API - /tables endpoints", () => { - let api: PublicAPIClient - const config = new TestConfiguration() + let api = new PublicAPIClient() + const config = new TestConfiguration(api) beforeAll(async () => { await config.beforeAll() - const app = await config.seedApp() - api = new PublicAPIClient(app.data._id) + const [_, app] = await config.applications.seed() + config.tables.appId = app._id }) afterAll(async () => { @@ -16,33 +18,29 @@ describe("Public API - /tables endpoints", () => { }) it("POST - Create a table", async () => { - const response = await api.post(`/tables`, { - body: require("./fixtures/table.json") - }) - const json = await response.json() - config.testContext.table = json.data + const [response, table] = await config.tables.create(generateTable()) + config.context = table expect(response).toHaveStatusCode(200) }) it("POST - Search tables", async () => { - const response = await api.post(`/tables/search`, { - body: { - name: config.testContext.table.name - } + const [response, table] = await config.tables.search({ + name: config.context.name, }) expect(response).toHaveStatusCode(200) }) it("GET - Retrieve a table", async () => { - const response = await api.get(`/tables/${config.testContext.table._id}`) + const [response, table] = await config.tables.read(config.context._id) expect(response).toHaveStatusCode(200) }) - it("PUT - update a table", async () => { - const response = await api.put(`/tables/${config.testContext.table._id}`, { - body: require("./fixtures/update_table.json") - }) + config.context.name = "updatedName" + const [response, table] = await config.tables.update( + config.context._id, + config.context + ) expect(response).toHaveStatusCode(200) }) }) diff --git a/qa-core/src/tests/public-api/users/fixtures/generate.ts b/qa-core/src/tests/public-api/users/fixtures/generate.ts deleted file mode 100644 index ca3c7b3c2c..0000000000 --- a/qa-core/src/tests/public-api/users/fixtures/generate.ts +++ /dev/null @@ -1,22 +0,0 @@ -import generator from "../../generator" -import { User } from "@budibase/types" - -const generate = (overrides = {}): User => ({ - tenantId: generator.word(), - email: generator.email(), - roles: { - [generator.string({ length: 32, alpha: true, numeric: true })]: generator.word(), - }, - password: generator.word(), - status: "active", - forceResetPassword: generator.bool(), - builder: { - global: generator.bool() - }, - admin: { - global: generator.bool() - }, - ...overrides -}) - -export default generate \ No newline at end of file diff --git a/qa-core/src/tests/public-api/users/fixtures/update_user.json b/qa-core/src/tests/public-api/users/fixtures/update_user.json deleted file mode 100644 index 72d24b3ee8..0000000000 --- a/qa-core/src/tests/public-api/users/fixtures/update_user.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "email": "test@budibase.com", - "roles": { - "sed_6d7": "sit ea amet", - "cupidatat_e16": "fugiat proident sed" - }, - "password": "cupidatat Lorem ad", - "status": "active", - "firstName": "QA", - "lastName": "Updated", - "forceResetPassword": true, - "builder": { - "global": true - }, - "admin": { - "global": false - } -} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/users/fixtures/user.json b/qa-core/src/tests/public-api/users/fixtures/user.json deleted file mode 100644 index b6fc9f49e6..0000000000 --- a/qa-core/src/tests/public-api/users/fixtures/user.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "email": "test@budibase.com", - "roles": { - "sed_6d7": "sit ea amet", - "cupidatat_e16": "fugiat proident sed" - }, - "password": "cupidatat Lorem ad", - "status": "active", - "firstName": "QA", - "lastName": "Test", - "forceResetPassword": true, - "builder": { - "global": true - }, - "admin": { - "global": false - } -} \ No newline at end of file diff --git a/qa-core/src/tests/public-api/users/users.spec.ts b/qa-core/src/tests/public-api/users/users.spec.ts index c18a78ca72..95d257c0f9 100644 --- a/qa-core/src/tests/public-api/users/users.spec.ts +++ b/qa-core/src/tests/public-api/users/users.spec.ts @@ -1,9 +1,11 @@ -import TestConfiguration from "../TestConfiguration" -import PublicAPIClient from "../PublicAPIClient" +import TestConfiguration from "../../../config/public-api/TestConfiguration" +import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" +import generateUser from "../../../config/public-api/fixtures/users" +import { User } from "../../../../../packages/server/src/api/controllers/public/mapping/types" describe("Public API - /users endpoints", () => { const api = new PublicAPIClient() - const config = new TestConfiguration() + const config = new TestConfiguration(api) beforeAll(async () => { await config.beforeAll() @@ -14,33 +16,29 @@ describe("Public API - /users endpoints", () => { }) it("POST - Create a user", async () => { - const response = await api.post(`/users`, { - body: require("./fixtures/user.json") - }) - const json = await response.json() - config.testContext.user = json.data + const [response, user] = await config.users.create(generateUser()) + config.context = user expect(response).toHaveStatusCode(200) }) it("POST - Search users", async () => { - const response = await api.post(`/users/search`, { - body: { - name: config.testContext.user.email - } + const [response, user] = await config.users.search({ + name: config.context.email, }) expect(response).toHaveStatusCode(200) }) it("GET - Retrieve a user", async () => { - const response = await api.get(`/users/${config.testContext.user._id}`) + const [response, user] = await config.users.read(config.context._id) expect(response).toHaveStatusCode(200) }) - it("PUT - update a user", async () => { - const response = await api.put(`/users/${config.testContext.user._id}`, { - body: require("./fixtures/update_user.json") - }) + config.context.firstName = "Updated First Name" + const [response, user] = await config.users.update( + config.context._id, + config.context + ) expect(response).toHaveStatusCode(200) }) }) diff --git a/qa-core/tsconfig.json b/qa-core/tsconfig.json index c305c3a4bd..0fa56727b8 100644 --- a/qa-core/tsconfig.json +++ b/qa-core/tsconfig.json @@ -14,8 +14,6 @@ "skipLibCheck": true, "paths": { "@budibase/types": ["../packages/types/src"], - "@budibase/backend-core": ["../packages/backend-core/src"], - "@budibase/backend-core/*": ["../packages/backend-core/*"] } }, "ts-node": { @@ -23,7 +21,6 @@ }, "references": [ { "path": "../packages/types" }, - { "path": "../packages/backend-core" }, ], "include": [ "src/**/*", diff --git a/qa-core/yarn.lock b/qa-core/yarn.lock index 5daa4d7ee7..9474c47b7c 100644 --- a/qa-core/yarn.lock +++ b/qa-core/yarn.lock @@ -290,7 +290,7 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/types@^1.3.4": +"@budibase/types@1.3.4": version "1.3.4" resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.3.4.tgz#25f087b024e843eb372e50c81f8f925fb39f1dfd" integrity sha512-ndyWs8yeCS7cpZjApDB1HhY6UUM2SRBUgAMCZOZaWABG9JHeCbx7x0e/pA2SZjswdMXqS5WmnEd3br5wuvUzJw== @@ -342,7 +342,7 @@ jest-util "^28.1.3" slash "^3.0.0" -"@jest/core@^28.1.3": +"@jest/core@^28.0.2", "@jest/core@^28.1.3": version "28.1.3" resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.3.tgz#0ebf2bd39840f1233cd5f2d1e6fc8b71bd5a1ac7" integrity sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA== @@ -712,7 +712,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^29.0.0": +"@types/jest@29.0.0": version "29.0.0" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.0.0.tgz#bc66835bf6b09d6a47e22c21d7f5b82692e60e72" integrity sha512-X6Zjz3WO4cT39Gkl0lZ2baFRaEMqJl5NC1OjElkwtNzAlbkr2K/WJXkBkH5VP0zx4Hgsd2TZYdOEfvp2Dxia+Q== @@ -720,7 +720,7 @@ expect "^29.0.0" pretty-format "^29.0.0" -"@types/node-fetch@^2.6.2": +"@types/node-fetch@2.6.2": version "2.6.2" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== @@ -979,7 +979,7 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chance@^1.1.8: +chance@1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/chance/-/chance-1.1.8.tgz#5d6c2b78c9170bf6eb9df7acdda04363085be909" integrity sha512-v7fi5Hj2VbR6dJEGRWLmJBA83LJMS47pkAbmROFxHWd9qmE1esHRZW8Clf1Fhzr3rjxnNZVCjOEv/ivFxeIMtg== @@ -1499,7 +1499,7 @@ jest-circus@^28.1.3: slash "^3.0.0" stack-utils "^2.0.3" -jest-cli@^28.1.3: +jest-cli@^28.0.2: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.3.tgz#558b33c577d06de55087b8448d373b9f654e46b2" integrity sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ== @@ -1866,15 +1866,14 @@ jest-worker@^28.1.3: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^28.0.2: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.3.tgz#e9c6a7eecdebe3548ca2b18894a50f45b36dfc6b" - integrity sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA== +jest@28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-28.0.2.tgz#41385ca21d009708bb9fc65e08663110e08e2cc0" + integrity sha512-COUtjybolW4koQvO7kCfq5kgbeeU5WbSJfVZprz4zbS8AL32+RAZZTUjBEyRRdpsXqss/pHIvSL7/P+LyMYHXg== dependencies: - "@jest/core" "^28.1.3" - "@jest/types" "^28.1.3" + "@jest/core" "^28.0.2" import-local "^3.0.2" - jest-cli "^28.1.3" + jest-cli "^28.0.2" joi@^17.4.0: version "17.6.0" @@ -2163,7 +2162,7 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -prettier@^2.7.1: +prettier@2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== @@ -2328,7 +2327,7 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" -start-server-and-test@^1.14.0: +start-server-and-test@1.14.0: version "1.14.0" resolved "https://registry.yarnpkg.com/start-server-and-test/-/start-server-and-test-1.14.0.tgz#c57f04f73eac15dd51733b551d775b40837fdde3" integrity sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw== @@ -2448,7 +2447,7 @@ through@2, through@~2.3, through@~2.3.1: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -timekeeper@^2.2.0: +timekeeper@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/timekeeper/-/timekeeper-2.2.0.tgz#9645731fce9e3280a18614a57a9d1b72af3ca368" integrity sha512-W3AmPTJWZkRwu+iSNxPIsLZ2ByADsOLbbLxe46UJyWj3mlYLlwucKiq+/dPm0l9wTzqoF3/2PH0AGFCebjq23A== @@ -2489,7 +2488,7 @@ ts-jest@28.0.8: semver "7.x" yargs-parser "^21.0.1" -ts-node@^10.9.1: +ts-node@10.9.1: version "10.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== @@ -2508,7 +2507,7 @@ ts-node@^10.9.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tsconfig-paths@^4.1.0: +tsconfig-paths@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.1.0.tgz#f8ef7d467f08ae3a695335bf1ece088c5538d2c1" integrity sha512-AHx4Euop/dXFC+Vx589alFba8QItjF+8hf8LtmuiCwHyI4rHXQtOOENaM8kvYf5fR0dRChy3wzWIZ9WbB7FWow== @@ -2532,10 +2531,10 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typescript@^4.8.2: - version "4.8.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790" - integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw== +typescript@4.7.3: + version "4.7.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" + integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== update-browserslist-db@^1.0.5: version "1.0.7" From f4760d703b83cc4327a04c0bb897a8a06b0ee50e Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 15 Sep 2022 09:48:44 +0100 Subject: [PATCH 4/8] better generation, and letting tests run in isolation --- .../public-api/TestConfiguration/rows.ts | 14 ++----------- .../public-api/TestConfiguration/tables.ts | 21 +++---------------- .../public-api/TestConfiguration/users.ts | 5 ++++- .../public-api/fixtures/applications.ts | 9 ++++++-- .../src/config/public-api/fixtures/tables.ts | 16 ++++++++------ .../src/config/public-api/fixtures/users.ts | 7 +++++-- .../applications/applications.spec.ts | 3 ++- .../src/tests/public-api/tables/rows.spec.ts | 10 +++++---- .../tests/public-api/tables/tables.spec.ts | 8 ++++--- .../src/tests/public-api/users/users.spec.ts | 3 ++- 10 files changed, 46 insertions(+), 50 deletions(-) diff --git a/qa-core/src/config/public-api/TestConfiguration/rows.ts b/qa-core/src/config/public-api/TestConfiguration/rows.ts index 4e39e4ec9e..8a85e2cd77 100644 --- a/qa-core/src/config/public-api/TestConfiguration/rows.ts +++ b/qa-core/src/config/public-api/TestConfiguration/rows.ts @@ -15,25 +15,16 @@ export default class RowApi { this.api = apiClient } - set appId(appId: string) { - this.headers = { - "x-budibase-app-id": appId, - } - } - async create(body: CreateRowParams): Promise<[Response, Row]> { const response = await this.api.post(`/tables/${this.tableId}/rows`, { body, - headers: this.headers, }) const json = await response.json() return [response, json.data] } async read(id: string): Promise<[Response, Row]> { - const response = await this.api.get(`/tables/${this.tableId}/rows/${id}`, { - headers: this.headers, - }) + const response = await this.api.get(`/tables/${this.tableId}/rows/${id}`) const json = await response.json() return [response, json.data] } @@ -41,7 +32,7 @@ export default class RowApi { async search(body: SearchInputParams): Promise<[Response, Row]> { const response = await this.api.post( `/tables/${this.tableId}/rows/search`, - { body, headers: this.headers } + { body } ) const json = await response.json() return [response, json.data] @@ -50,7 +41,6 @@ export default class RowApi { async update(id: string, body: Row): Promise<[Response, Row]> { const response = await this.api.put(`/tables/${this.tableId}/rows/${id}`, { body, - headers: this.headers, }) const json = await response.json() return [response, json.data] diff --git a/qa-core/src/config/public-api/TestConfiguration/tables.ts b/qa-core/src/config/public-api/TestConfiguration/tables.ts index c0b7e088e1..847b4d00cc 100644 --- a/qa-core/src/config/public-api/TestConfiguration/tables.ts +++ b/qa-core/src/config/public-api/TestConfiguration/tables.ts @@ -19,43 +19,28 @@ export default class TableApi { return this.create(generateTable()) } - set appId(appId: string) { - this.headers = { - "x-budibase-app-id": appId, - } - } - async create(body: CreateTableParams): Promise<[Response, Table]> { const response = await this.api.post(`/tables`, { body, - headers: this.headers, }) const json = await response.json() return [response, json.data] } async read(id: string): Promise<[Response, Table]> { - const response = await this.api.get(`/tables/${id}`, { - headers: this.headers, - }) + const response = await this.api.get(`/tables/${id}`) const json = await response.json() return [response, json.data] } async search(body: SearchInputParams): Promise<[Response, Table]> { - const response = await this.api.post(`/tables/search`, { - body, - headers: this.headers, - }) + const response = await this.api.post(`/tables/search`, { body }) const json = await response.json() return [response, json.data] } async update(id: string, body: Table): Promise<[Response, Table]> { - const response = await this.api.put(`/tables/${id}`, { - body, - headers: this.headers, - }) + const response = await this.api.put(`/tables/${id}`, { body }) const json = await response.json() return [response, json.data] } diff --git a/qa-core/src/config/public-api/TestConfiguration/users.ts b/qa-core/src/config/public-api/TestConfiguration/users.ts index 79217620aa..34c5f57a1a 100644 --- a/qa-core/src/config/public-api/TestConfiguration/users.ts +++ b/qa-core/src/config/public-api/TestConfiguration/users.ts @@ -5,6 +5,7 @@ import { User, } from "../../../../../packages/server/src/api/controllers/public/mapping/types" import { Response } from "node-fetch" +import generateUser from "../fixtures/users" export default class UserApi { api: PublicAPIClient @@ -13,7 +14,9 @@ export default class UserApi { this.api = apiClient } - async seed() {} + async seed() { + return this.create(generateUser()) + } async create(body: CreateUserParams): Promise<[Response, User]> { const response = await this.api.post(`/users`, { body }) diff --git a/qa-core/src/config/public-api/fixtures/applications.ts b/qa-core/src/config/public-api/fixtures/applications.ts index 25456f4c4b..731c240c04 100644 --- a/qa-core/src/config/public-api/fixtures/applications.ts +++ b/qa-core/src/config/public-api/fixtures/applications.ts @@ -1,7 +1,12 @@ import generator from "../TestConfiguration/generator" -import { CreateApplicationParams } from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { + Application, + CreateApplicationParams, +} from "../../../../../packages/server/src/api/controllers/public/mapping/types" -const generate = (overrides = {}): CreateApplicationParams => ({ +const generate = ( + overrides: Partial = {} +): CreateApplicationParams => ({ name: generator.word(), url: `/${generator.word()}`, ...overrides, diff --git a/qa-core/src/config/public-api/fixtures/tables.ts b/qa-core/src/config/public-api/fixtures/tables.ts index bbf93322c3..8d47076e5c 100644 --- a/qa-core/src/config/public-api/fixtures/tables.ts +++ b/qa-core/src/config/public-api/fixtures/tables.ts @@ -1,10 +1,14 @@ import { CreateRowParams, CreateTableParams, + Row, + Table, } from "../../../../../packages/server/src/api/controllers/public/mapping/types" import generator from "../TestConfiguration/generator" -export const generateTable = (overrides = {}): CreateTableParams => ({ +export const generateTable = ( + overrides: Partial
= {} +): CreateTableParams => ({ name: generator.word(), primaryDisplay: "sasa", schema: { @@ -20,7 +24,7 @@ export const generateTable = (overrides = {}): CreateTableParams => ({ }, "Created By": { autocolumn: true, - fieldName: "test12-Created By", + fieldName: generator.word(), name: "Created By", relationshipType: "many-to-many", tableId: "ta_users", @@ -37,7 +41,7 @@ export const generateTable = (overrides = {}): CreateTableParams => ({ }, "Updated By": { autocolumn: true, - fieldName: "test12-Updated By", + fieldName: generator.word(), name: "Updated By", relationshipType: "many-to-many", tableId: "ta_users", @@ -47,10 +51,10 @@ export const generateTable = (overrides = {}): CreateTableParams => ({ ...overrides, }) -export const generateRow = (overrides = {}): CreateRowParams => ({ +export const generateRow = (overrides: Partial = {}): CreateRowParams => ({ type: "row", tableId: "seed_table", - sasa: "Mike", - relationship: ["ro_ta_"], + sasa: generator.word(), + relationship: [generator.string({ length: 32, alpha: true, numeric: true })], ...overrides, }) diff --git a/qa-core/src/config/public-api/fixtures/users.ts b/qa-core/src/config/public-api/fixtures/users.ts index 52124024e7..aaca5f2480 100644 --- a/qa-core/src/config/public-api/fixtures/users.ts +++ b/qa-core/src/config/public-api/fixtures/users.ts @@ -1,7 +1,10 @@ -import { CreateUserParams } from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { + CreateUserParams, + User, +} from "../../../../../packages/server/src/api/controllers/public/mapping/types" import generator from "../TestConfiguration/generator" -const generate = (overrides = {}): CreateUserParams => ({ +const generate = (overrides: Partial = {}): CreateUserParams => ({ email: generator.email(), roles: { [generator.string({ length: 32, alpha: true, numeric: true })]: diff --git a/qa-core/src/tests/public-api/applications/applications.spec.ts b/qa-core/src/tests/public-api/applications/applications.spec.ts index 1031f511b4..59a24861af 100644 --- a/qa-core/src/tests/public-api/applications/applications.spec.ts +++ b/qa-core/src/tests/public-api/applications/applications.spec.ts @@ -9,6 +9,8 @@ describe("Public API - /applications endpoints", () => { beforeAll(async () => { await config.beforeAll() + const [response, app] = await config.applications.seed() + config.context = app }) afterAll(async () => { @@ -17,7 +19,6 @@ describe("Public API - /applications endpoints", () => { it("POST - Create an application", async () => { const [response, app] = await config.applications.create(generateApp()) - config.context = app expect(response).toHaveStatusCode(200) }) diff --git a/qa-core/src/tests/public-api/tables/rows.spec.ts b/qa-core/src/tests/public-api/tables/rows.spec.ts index 66d46208cc..f34c4cde29 100644 --- a/qa-core/src/tests/public-api/tables/rows.spec.ts +++ b/qa-core/src/tests/public-api/tables/rows.spec.ts @@ -12,11 +12,14 @@ describe("Public API - /rows endpoints", () => { await config.beforeAll() const [appResp, app] = await config.applications.seed() - config.tables.appId = app._id - const [tableResp, table] = await config.tables.seed() + config.tables.api.appId = app._id + config.rows.api.appId = app._id - config.rows.appId = app._id + const [tableResp, table] = await config.tables.seed() config.rows.tableId = table._id + + const [response, row] = await config.rows.create(generateRow()) + config.context = row }) afterAll(async () => { @@ -25,7 +28,6 @@ describe("Public API - /rows endpoints", () => { it("POST - Create a row", async () => { const [response, row] = await config.rows.create(generateRow()) - config.context = row expect(response).toHaveStatusCode(200) }) diff --git a/qa-core/src/tests/public-api/tables/tables.spec.ts b/qa-core/src/tests/public-api/tables/tables.spec.ts index 9dfdc8cdc0..c2f50d3e8e 100644 --- a/qa-core/src/tests/public-api/tables/tables.spec.ts +++ b/qa-core/src/tests/public-api/tables/tables.spec.ts @@ -9,8 +9,11 @@ describe("Public API - /tables endpoints", () => { beforeAll(async () => { await config.beforeAll() - const [_, app] = await config.applications.seed() - config.tables.appId = app._id + const [appResp, app] = await config.applications.seed() + config.tables.api.appId = app._id + + const [tableResp, table] = await config.tables.seed() + config.context = table }) afterAll(async () => { @@ -19,7 +22,6 @@ describe("Public API - /tables endpoints", () => { it("POST - Create a table", async () => { const [response, table] = await config.tables.create(generateTable()) - config.context = table expect(response).toHaveStatusCode(200) }) diff --git a/qa-core/src/tests/public-api/users/users.spec.ts b/qa-core/src/tests/public-api/users/users.spec.ts index 95d257c0f9..b981deb786 100644 --- a/qa-core/src/tests/public-api/users/users.spec.ts +++ b/qa-core/src/tests/public-api/users/users.spec.ts @@ -9,6 +9,8 @@ describe("Public API - /users endpoints", () => { beforeAll(async () => { await config.beforeAll() + const [response, user] = await config.users.seed() + config.context = user }) afterAll(async () => { @@ -17,7 +19,6 @@ describe("Public API - /users endpoints", () => { it("POST - Create a user", async () => { const [response, user] = await config.users.create(generateUser()) - config.context = user expect(response).toHaveStatusCode(200) }) From 65d41fdd20273db194445a8456735d900500470b Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 15 Sep 2022 19:51:11 +0100 Subject: [PATCH 5/8] better tests and cleaner import for server --- .github/workflows/budibase_ci.yml | 3 +- packages/backend-core/yarn.lock | 5 + packages/server/specs/openapi.json | 221 +++++++++--------- packages/server/specs/openapi.yaml | 184 +++++++-------- packages/server/specs/resources/misc.js | 116 +++++++++ .../api/controllers/public/mapping/types.ts | 2 +- packages/server/src/api/routes/public/rows.ts | 83 +------ packages/server/src/definitions/openapi.ts | 105 ++++----- qa-core/package.json | 3 +- .../TestConfiguration/applications.ts | 4 +- .../public-api/TestConfiguration/rows.ts | 9 +- .../public-api/TestConfiguration/tables.ts | 4 +- .../public-api/TestConfiguration/users.ts | 4 +- .../public-api/fixtures/applications.ts | 2 +- .../src/config/public-api/fixtures/tables.ts | 10 +- .../src/config/public-api/fixtures/users.ts | 2 +- .../applications/applications.spec.ts | 9 +- .../src/tests/public-api/tables/rows.spec.ts | 25 +- .../tests/public-api/tables/tables.spec.ts | 8 +- .../src/tests/public-api/users/users.spec.ts | 10 +- qa-core/tsconfig.json | 1 + 21 files changed, 444 insertions(+), 366 deletions(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 23cdfba236..3715979922 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -60,7 +60,8 @@ jobs: # install: false # command: yarn test:e2e:ci - - run: | + - name: QA Core Integration Tests + run: | cd qa-core yarn yarn api:test:ci \ No newline at end of file diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index 22c17a9444..2e62aea734 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -1377,6 +1377,11 @@ bcrypt@5.0.1: "@mapbox/node-pre-gyp" "^1.0.0" node-addon-api "^3.1.0" +bcryptjs@2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" + integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" diff --git a/packages/server/specs/openapi.json b/packages/server/specs/openapi.json index 97c0fa9551..f8539b9f7f 100644 --- a/packages/server/specs/openapi.json +++ b/packages/server/specs/openapi.json @@ -1659,6 +1659,117 @@ "data" ] }, + "rowSearch": { + "type": "object", + "properties": { + "query": { + "type": "object", + "properties": { + "allOr": { + "type": "boolean", + "description": "Specifies that a row should be returned if it satisfies any of the specified options, rather than requiring it to fulfill all the search parameters. This defaults to false, meaning AND logic will be used." + }, + "string": { + "type": "object", + "example": { + "columnName1": "value", + "columnName2": "value" + }, + "description": "A map of field name to the string to search for, this will look for rows that have a value starting with the string value.", + "additionalProperties": { + "type": "string", + "description": "The value to search for in the column." + } + }, + "fuzzy": { + "type": "object", + "description": "A fuzzy search, only supported by internal tables." + }, + "range": { + "type": "object", + "description": "Searches within a range, the format of this must be in the format of an object with a \"low\" and \"high\" property.", + "example": { + "columnName1": { + "low": 10, + "high": 20 + } + } + }, + "equal": { + "type": "object", + "description": "Searches for rows that have a column value that is exactly the value set." + }, + "notEqual": { + "type": "object", + "description": "Searches for any row which does not contain the specified column value." + }, + "empty": { + "type": "object", + "description": "Searches for rows which do not contain the specified column. The object should simply contain keys of the column names, these can map to any value.", + "example": { + "columnName1": "" + } + }, + "notEmpty": { + "type": "object", + "description": "Searches for rows which have the specified column." + }, + "oneOf": { + "type": "object", + "description": "Searches for rows which have a column value that is any of the specified values. The format of this must be columnName -> [value1, value2]." + } + } + }, + "paginate": { + "type": "boolean", + "description": "Enables pagination, by default this is disabled." + }, + "bookmark": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ], + "description": "If retrieving another page, the bookmark from the previous request must be supplied." + }, + "limit": { + "type": "integer", + "description": "The maximum number of rows to return, useful when paginating, for internal tables this will be limited to 1000, for SQL tables it will be 5000." + }, + "sort": { + "type": "object", + "description": "A set of parameters describing the sort behaviour of the search.", + "properties": { + "order": { + "type": "string", + "enum": [ + "ascending", + "descending" + ], + "description": "The order of the sort, by default this is ascending." + }, + "column": { + "type": "string", + "description": "The name of the column by which the rows will be sorted." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number" + ], + "description": "Defines whether the column should be treated as a string or as numbers when sorting." + } + } + } + }, + "required": [ + "query" + ] + }, "nameSearch": { "type": "object", "properties": { @@ -2129,115 +2240,7 @@ "content": { "application/json": { "schema": { - "type": "object", - "required": [ - "query" - ], - "properties": { - "query": { - "type": "object", - "properties": { - "allOr": { - "type": "boolean", - "description": "Specifies that a row should be returned if it satisfies any of the specified options, rather than requiring it to fulfill all the search parameters. This defaults to false, meaning AND logic will be used." - }, - "string": { - "type": "object", - "example": { - "columnName1": "value", - "columnName2": "value" - }, - "description": "A map of field name to the string to search for, this will look for rows that have a value starting with the string value.", - "additionalProperties": { - "type": "string", - "description": "The value to search for in the column." - } - }, - "fuzzy": { - "type": "object", - "description": "A fuzzy search, only supported by internal tables." - }, - "range": { - "type": "object", - "description": "Searches within a range, the format of this must be in the format of an object with a \"low\" and \"high\" property.", - "example": { - "columnName1": { - "low": 10, - "high": 20 - } - } - }, - "equal": { - "type": "object", - "description": "Searches for rows that have a column value that is exactly the value set." - }, - "notEqual": { - "type": "object", - "description": "Searches for any row which does not contain the specified column value." - }, - "empty": { - "type": "object", - "description": "Searches for rows which do not contain the specified column. The object should simply contain keys of the column names, these can map to any value.", - "example": { - "columnName1": "" - } - }, - "notEmpty": { - "type": "object", - "description": "Searches for rows which have the specified column." - }, - "oneOf": { - "type": "object", - "description": "Searches for rows which have a column value that is any of the specified values. The format of this must be columnName -> [value1, value2]." - } - } - }, - "paginate": { - "type": "boolean", - "description": "Enables pagination, by default this is disabled." - }, - "bookmark": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "integer" - } - ], - "description": "If retrieving another page, the bookmark from the previous request must be supplied." - }, - "limit": { - "type": "integer", - "description": "The maximum number of rows to return, useful when paginating, for internal tables this will be limited to 1000, for SQL tables it will be 5000." - }, - "sort": { - "type": "object", - "description": "A set of parameters describing the sort behaviour of the search.", - "properties": { - "order": { - "type": "string", - "enum": [ - "ascending", - "descending" - ], - "description": "The order of the sort, by default this is ascending." - }, - "column": { - "type": "string", - "description": "The name of the column by which the rows will be sorted." - }, - "type": { - "type": "string", - "enum": [ - "string", - "number" - ], - "description": "Defines whether the column should be treated as a string or as numbers when sorting." - } - } - } - } + "$ref": "#/components/schemas/rowSearch" } } } diff --git a/packages/server/specs/openapi.yaml b/packages/server/specs/openapi.yaml index 3bcb893862..3cd29791af 100644 --- a/packages/server/specs/openapi.yaml +++ b/packages/server/specs/openapi.yaml @@ -1264,6 +1264,98 @@ components: - _id required: - data + rowSearch: + type: object + properties: + query: + type: object + properties: + allOr: + type: boolean + description: Specifies that a row should be returned if it satisfies any of the + specified options, rather than requiring it to fulfill all the + search parameters. This defaults to false, meaning AND logic + will be used. + string: + type: object + example: + columnName1: value + columnName2: value + description: A map of field name to the string to search for, this will look for + rows that have a value starting with the string value. + additionalProperties: + type: string + description: The value to search for in the column. + fuzzy: + type: object + description: A fuzzy search, only supported by internal tables. + range: + type: object + description: Searches within a range, the format of this must be in the format + of an object with a "low" and "high" property. + example: + columnName1: + low: 10 + high: 20 + equal: + type: object + description: Searches for rows that have a column value that is exactly the + value set. + notEqual: + type: object + description: Searches for any row which does not contain the specified column + value. + empty: + type: object + description: Searches for rows which do not contain the specified column. The + object should simply contain keys of the column names, these can + map to any value. + example: + columnName1: "" + notEmpty: + type: object + description: Searches for rows which have the specified column. + oneOf: + type: object + description: Searches for rows which have a column value that is any of the + specified values. The format of this must be columnName -> + [value1, value2]. + paginate: + type: boolean + description: Enables pagination, by default this is disabled. + bookmark: + oneOf: + - type: string + - type: integer + description: If retrieving another page, the bookmark from the previous request + must be supplied. + limit: + type: integer + description: The maximum number of rows to return, useful when paginating, for + internal tables this will be limited to 1000, for SQL tables it will + be 5000. + sort: + type: object + description: A set of parameters describing the sort behaviour of the search. + properties: + order: + type: string + enum: + - ascending + - descending + description: The order of the sort, by default this is ascending. + column: + type: string + description: The name of the column by which the rows will be sorted. + type: + type: string + enum: + - string + - number + description: Defines whether the column should be treated as a string or as + numbers when sorting. + required: + - query nameSearch: type: object properties: @@ -1544,97 +1636,7 @@ paths: content: application/json: schema: - type: object - required: - - query - properties: - query: - type: object - properties: - allOr: - type: boolean - description: Specifies that a row should be returned if it satisfies any of the - specified options, rather than requiring it to fulfill - all the search parameters. This defaults to false, - meaning AND logic will be used. - string: - type: object - example: - columnName1: value - columnName2: value - description: A map of field name to the string to search for, this will look for - rows that have a value starting with the string value. - additionalProperties: - type: string - description: The value to search for in the column. - fuzzy: - type: object - description: A fuzzy search, only supported by internal tables. - range: - type: object - description: Searches within a range, the format of this must be in the format - of an object with a "low" and "high" property. - example: - columnName1: - low: 10 - high: 20 - equal: - type: object - description: Searches for rows that have a column value that is exactly the - value set. - notEqual: - type: object - description: Searches for any row which does not contain the specified column - value. - empty: - type: object - description: Searches for rows which do not contain the specified column. The - object should simply contain keys of the column names, - these can map to any value. - example: - columnName1: "" - notEmpty: - type: object - description: Searches for rows which have the specified column. - oneOf: - type: object - description: Searches for rows which have a column value that is any of the - specified values. The format of this must be columnName - -> [value1, value2]. - paginate: - type: boolean - description: Enables pagination, by default this is disabled. - bookmark: - oneOf: - - type: string - - type: integer - description: If retrieving another page, the bookmark from the previous request - must be supplied. - limit: - type: integer - description: The maximum number of rows to return, useful when paginating, for - internal tables this will be limited to 1000, for SQL tables - it will be 5000. - sort: - type: object - description: A set of parameters describing the sort behaviour of the search. - properties: - order: - type: string - enum: - - ascending - - descending - description: The order of the sort, by default this is ascending. - column: - type: string - description: The name of the column by which the rows will be sorted. - type: - type: string - enum: - - string - - number - description: Defines whether the column should be treated as a string or as - numbers when sorting. + $ref: "#/components/schemas/rowSearch" responses: "200": description: The response will contain an array of rows that match the search diff --git a/packages/server/specs/resources/misc.js b/packages/server/specs/resources/misc.js index bf92680ca8..32a81da9ec 100644 --- a/packages/server/specs/resources/misc.js +++ b/packages/server/specs/resources/misc.js @@ -2,6 +2,122 @@ const { object } = require("./utils") const Resource = require("./utils/Resource") module.exports = new Resource().setSchemas({ + rowSearch: object( + { + query: { + type: "object", + properties: { + allOr: { + type: "boolean", + description: + "Specifies that a row should be returned if it satisfies any of the specified options, rather than requiring it to fulfill all the search parameters. This defaults to false, meaning AND logic will be used.", + }, + string: { + type: "object", + example: { + columnName1: "value", + columnName2: "value", + }, + description: + "A map of field name to the string to search for, this will look for rows that have a value starting with the string value.", + additionalProperties: { + type: "string", + description: "The value to search for in the column.", + }, + }, + fuzzy: { + type: "object", + description: "A fuzzy search, only supported by internal tables.", + }, + range: { + type: "object", + description: + 'Searches within a range, the format of this must be in the format of an object with a "low" and "high" property.', + example: { + columnName1: { + low: 10, + high: 20, + }, + }, + }, + equal: { + type: "object", + description: + "Searches for rows that have a column value that is exactly the value set.", + }, + notEqual: { + type: "object", + description: + "Searches for any row which does not contain the specified column value.", + }, + empty: { + type: "object", + description: + "Searches for rows which do not contain the specified column. The object should simply contain keys of the column names, these can map to any value.", + example: { + columnName1: "", + }, + }, + notEmpty: { + type: "object", + description: "Searches for rows which have the specified column.", + }, + oneOf: { + type: "object", + description: + "Searches for rows which have a column value that is any of the specified values. The format of this must be columnName -> [value1, value2].", + }, + }, + }, + paginate: { + type: "boolean", + description: "Enables pagination, by default this is disabled.", + }, + bookmark: { + oneOf: [ + { + type: "string", + }, + { + type: "integer", + }, + ], + description: + "If retrieving another page, the bookmark from the previous request must be supplied.", + }, + limit: { + type: "integer", + description: + "The maximum number of rows to return, useful when paginating, for internal tables this will be limited to 1000, for SQL tables it will be 5000.", + }, + sort: { + type: "object", + description: + "A set of parameters describing the sort behaviour of the search.", + properties: { + order: { + type: "string", + enum: ["ascending", "descending"], + description: "The order of the sort, by default this is ascending.", + }, + column: { + type: "string", + description: + "The name of the column by which the rows will be sorted.", + }, + type: { + type: "string", + enum: ["string", "number"], + description: + "Defines whether the column should be treated as a string or as numbers when sorting.", + }, + }, + }, + }, + { + required: ["query"], + } + ), nameSearch: object({ name: { type: "string", diff --git a/packages/server/src/api/controllers/public/mapping/types.ts b/packages/server/src/api/controllers/public/mapping/types.ts index 5d161ec17a..e3c8719d87 100644 --- a/packages/server/src/api/controllers/public/mapping/types.ts +++ b/packages/server/src/api/controllers/public/mapping/types.ts @@ -18,4 +18,4 @@ export type CreateUserParams = components["schemas"]["user"] export type SearchInputParams = | components["schemas"]["nameSearch"] - | components["schemas"]["querySearch"] + | components["schemas"]["rowSearch"] diff --git a/packages/server/src/api/routes/public/rows.ts b/packages/server/src/api/routes/public/rows.ts index 7c9e4f7af7..80da073e3e 100644 --- a/packages/server/src/api/routes/public/rows.ts +++ b/packages/server/src/api/routes/public/rows.ts @@ -143,88 +143,7 @@ read.push(new Endpoint("get", "/tables/:tableId/rows/:rowId", controller.read)) * content: * application/json: * schema: - * type: object - * required: - * - query - * properties: - * query: - * type: object - * properties: - * allOr: - * type: boolean - * description: Specifies that a row should be returned if it satisfies - * any of the specified options, rather than requiring it to fulfill all - * the search parameters. This defaults to false, meaning AND logic will be used. - * string: - * type: object - * example: - * columnName1: value - * columnName2: value - * description: A map of field name to the string to search for, - * this will look for rows that have a value starting with the - * string value. - * additionalProperties: - * type: string - * description: The value to search for in the column. - * fuzzy: - * type: object - * description: A fuzzy search, only supported by internal tables. - * range: - * type: object - * description: Searches within a range, the format of this must be - * in the format of an object with a "low" and "high" property. - * example: - * columnName1: { low: 10, high: 20 } - * equal: - * type: object - * description: Searches for rows that have a column value that is - * exactly the value set. - * notEqual: - * type: object - * description: Searches for any row which does not contain the specified - * column value. - * empty: - * type: object - * description: Searches for rows which do not contain the specified column. - * The object should simply contain keys of the column names, these - * can map to any value. - * example: - * columnName1: "" - * notEmpty: - * type: object - * description: Searches for rows which have the specified column. - * oneOf: - * type: object - * description: Searches for rows which have a column value that is any - * of the specified values. The format of this must be columnName -> [value1, value2]. - * paginate: - * type: boolean - * description: Enables pagination, by default this is disabled. - * bookmark: - * oneOf: - * - type: string - * - type: integer - * description: If retrieving another page, the bookmark from the previous request must be supplied. - * limit: - * type: integer - * description: The maximum number of rows to return, useful when paginating, for internal tables this - * will be limited to 1000, for SQL tables it will be 5000. - * sort: - * type: object - * description: A set of parameters describing the sort behaviour of the search. - * properties: - * order: - * type: string - * enum: [ascending, descending] - * description: The order of the sort, by default this is ascending. - * column: - * type: string - * description: The name of the column by which the rows will be sorted. - * type: - * type: string - * enum: [string, number] - * description: Defines whether the column should be treated as a string - * or as numbers when sorting. + * $ref: '#/components/schemas/rowSearch' * responses: * 200: * description: The response will contain an array of rows that match the search parameters. diff --git a/packages/server/src/definitions/openapi.ts b/packages/server/src/definitions/openapi.ts index 486901acad..a4bd0c1e3e 100644 --- a/packages/server/src/definitions/openapi.ts +++ b/packages/server/src/definitions/openapi.ts @@ -278,58 +278,7 @@ export interface paths { }; requestBody: { content: { - "application/json": { - query: { - /** @description Specifies that a row should be returned if it satisfies any of the specified options, rather than requiring it to fulfill all the search parameters. This defaults to false, meaning AND logic will be used. */ - allOr?: boolean; - /** - * @description A map of field name to the string to search for, this will look for rows that have a value starting with the string value. - * @example [object Object] - */ - string?: { [key: string]: string }; - /** @description A fuzzy search, only supported by internal tables. */ - fuzzy?: { [key: string]: unknown }; - /** - * @description Searches within a range, the format of this must be in the format of an object with a "low" and "high" property. - * @example [object Object] - */ - range?: { [key: string]: unknown }; - /** @description Searches for rows that have a column value that is exactly the value set. */ - equal?: { [key: string]: unknown }; - /** @description Searches for any row which does not contain the specified column value. */ - notEqual?: { [key: string]: unknown }; - /** - * @description Searches for rows which do not contain the specified column. The object should simply contain keys of the column names, these can map to any value. - * @example [object Object] - */ - empty?: { [key: string]: unknown }; - /** @description Searches for rows which have the specified column. */ - notEmpty?: { [key: string]: unknown }; - /** @description Searches for rows which have a column value that is any of the specified values. The format of this must be columnName -> [value1, value2]. */ - oneOf?: { [key: string]: unknown }; - }; - /** @description Enables pagination, by default this is disabled. */ - paginate?: boolean; - /** @description If retrieving another page, the bookmark from the previous request must be supplied. */ - bookmark?: string | number; - /** @description The maximum number of rows to return, useful when paginating, for internal tables this will be limited to 1000, for SQL tables it will be 5000. */ - limit?: number; - /** @description A set of parameters describing the sort behaviour of the search. */ - sort?: { - /** - * @description The order of the sort, by default this is ascending. - * @enum {string} - */ - order?: "ascending" | "descending"; - /** @description The name of the column by which the rows will be sorted. */ - column?: string; - /** - * @description Defines whether the column should be treated as a string or as numbers when sorting. - * @enum {string} - */ - type?: "string" | "number"; - }; - }; + "application/json": components["schemas"]["rowSearch"]; }; }; }; @@ -1105,6 +1054,58 @@ export interface components { _id: string; }[]; }; + rowSearch: { + query: { + /** @description Specifies that a row should be returned if it satisfies any of the specified options, rather than requiring it to fulfill all the search parameters. This defaults to false, meaning AND logic will be used. */ + allOr?: boolean; + /** + * @description A map of field name to the string to search for, this will look for rows that have a value starting with the string value. + * @example [object Object] + */ + string?: { [key: string]: string }; + /** @description A fuzzy search, only supported by internal tables. */ + fuzzy?: { [key: string]: unknown }; + /** + * @description Searches within a range, the format of this must be in the format of an object with a "low" and "high" property. + * @example [object Object] + */ + range?: { [key: string]: unknown }; + /** @description Searches for rows that have a column value that is exactly the value set. */ + equal?: { [key: string]: unknown }; + /** @description Searches for any row which does not contain the specified column value. */ + notEqual?: { [key: string]: unknown }; + /** + * @description Searches for rows which do not contain the specified column. The object should simply contain keys of the column names, these can map to any value. + * @example [object Object] + */ + empty?: { [key: string]: unknown }; + /** @description Searches for rows which have the specified column. */ + notEmpty?: { [key: string]: unknown }; + /** @description Searches for rows which have a column value that is any of the specified values. The format of this must be columnName -> [value1, value2]. */ + oneOf?: { [key: string]: unknown }; + }; + /** @description Enables pagination, by default this is disabled. */ + paginate?: boolean; + /** @description If retrieving another page, the bookmark from the previous request must be supplied. */ + bookmark?: string | number; + /** @description The maximum number of rows to return, useful when paginating, for internal tables this will be limited to 1000, for SQL tables it will be 5000. */ + limit?: number; + /** @description A set of parameters describing the sort behaviour of the search. */ + sort?: { + /** + * @description The order of the sort, by default this is ascending. + * @enum {string} + */ + order?: "ascending" | "descending"; + /** @description The name of the column by which the rows will be sorted. */ + column?: string; + /** + * @description Defines whether the column should be treated as a string or as numbers when sorting. + * @enum {string} + */ + type?: "string" | "number"; + }; + }; nameSearch: { /** @description The name to be used when searching - this will be used in a case insensitive starts with match. */ name: string; diff --git a/qa-core/package.json b/qa-core/package.json index 2103f1670e..f82849c92e 100644 --- a/qa-core/package.json +++ b/qa-core/package.json @@ -21,7 +21,8 @@ "preset": "ts-jest", "testEnvironment": "node", "moduleNameMapper": { - "@budibase/types": "/../packages/types/src" + "@budibase/types": "/../packages/types/src", + "@budibase/server": "/../packages/server/src" }, "setupFiles": [ "./scripts/jestSetup.js" diff --git a/qa-core/src/config/public-api/TestConfiguration/applications.ts b/qa-core/src/config/public-api/TestConfiguration/applications.ts index 6232c14c28..79de8f570d 100644 --- a/qa-core/src/config/public-api/TestConfiguration/applications.ts +++ b/qa-core/src/config/public-api/TestConfiguration/applications.ts @@ -3,7 +3,7 @@ import { Application, SearchInputParams, CreateApplicationParams, -} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +} from "@budibase/server/api/controllers/public/mapping/types" import { Response } from "node-fetch" import generateApp from "../fixtures/applications" @@ -32,7 +32,7 @@ export default class AppApi { return [response, json.data] } - async search(body: SearchInputParams): Promise<[Response, Application]> { + async search(body: SearchInputParams): Promise<[Response, [Application]]> { const response = await this.api.post(`/applications/search`, { body }) const json = await response.json() return [response, json.data] diff --git a/qa-core/src/config/public-api/TestConfiguration/rows.ts b/qa-core/src/config/public-api/TestConfiguration/rows.ts index 8a85e2cd77..c3689de5d8 100644 --- a/qa-core/src/config/public-api/TestConfiguration/rows.ts +++ b/qa-core/src/config/public-api/TestConfiguration/rows.ts @@ -3,8 +3,9 @@ import { CreateRowParams, Row, SearchInputParams, -} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +} from "@budibase/server/api/controllers/public/mapping/types" import { HeadersInit, Response } from "node-fetch" +import { generateRow } from "../fixtures/tables" export default class RowApi { api: PublicAPIClient @@ -15,6 +16,10 @@ export default class RowApi { this.api = apiClient } + async seed(tableId: string) { + return this.create(generateRow({ tableId })) + } + async create(body: CreateRowParams): Promise<[Response, Row]> { const response = await this.api.post(`/tables/${this.tableId}/rows`, { body, @@ -29,7 +34,7 @@ export default class RowApi { return [response, json.data] } - async search(body: SearchInputParams): Promise<[Response, Row]> { + async search(body: SearchInputParams): Promise<[Response, [Row]]> { const response = await this.api.post( `/tables/${this.tableId}/rows/search`, { body } diff --git a/qa-core/src/config/public-api/TestConfiguration/tables.ts b/qa-core/src/config/public-api/TestConfiguration/tables.ts index 847b4d00cc..9a1c9db019 100644 --- a/qa-core/src/config/public-api/TestConfiguration/tables.ts +++ b/qa-core/src/config/public-api/TestConfiguration/tables.ts @@ -3,7 +3,7 @@ import { Table, SearchInputParams, CreateTableParams, -} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +} from "@budibase/server/api/controllers/public/mapping/types" import { HeadersInit, Response } from "node-fetch" import { generateTable } from "../fixtures/tables" @@ -33,7 +33,7 @@ export default class TableApi { return [response, json.data] } - async search(body: SearchInputParams): Promise<[Response, Table]> { + async search(body: SearchInputParams): Promise<[Response, [Table]]> { const response = await this.api.post(`/tables/search`, { body }) const json = await response.json() return [response, json.data] diff --git a/qa-core/src/config/public-api/TestConfiguration/users.ts b/qa-core/src/config/public-api/TestConfiguration/users.ts index 34c5f57a1a..c332777aed 100644 --- a/qa-core/src/config/public-api/TestConfiguration/users.ts +++ b/qa-core/src/config/public-api/TestConfiguration/users.ts @@ -3,7 +3,7 @@ import { CreateUserParams, SearchInputParams, User, -} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +} from "@budibase/server/api/controllers/public/mapping/types" import { Response } from "node-fetch" import generateUser from "../fixtures/users" @@ -30,7 +30,7 @@ export default class UserApi { return [response, json.data] } - async search(body: SearchInputParams): Promise<[Response, User]> { + async search(body: SearchInputParams): Promise<[Response, [User]]> { const response = await this.api.post(`/users/search`, { body }) const json = await response.json() return [response, json.data] diff --git a/qa-core/src/config/public-api/fixtures/applications.ts b/qa-core/src/config/public-api/fixtures/applications.ts index 731c240c04..3b58faa95f 100644 --- a/qa-core/src/config/public-api/fixtures/applications.ts +++ b/qa-core/src/config/public-api/fixtures/applications.ts @@ -2,7 +2,7 @@ import generator from "../TestConfiguration/generator" import { Application, CreateApplicationParams, -} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +} from "@budibase/server/api/controllers/public/mapping/types" const generate = ( overrides: Partial = {} diff --git a/qa-core/src/config/public-api/fixtures/tables.ts b/qa-core/src/config/public-api/fixtures/tables.ts index 8d47076e5c..cf76855439 100644 --- a/qa-core/src/config/public-api/fixtures/tables.ts +++ b/qa-core/src/config/public-api/fixtures/tables.ts @@ -3,14 +3,14 @@ import { CreateTableParams, Row, Table, -} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +} from "@budibase/server/api/controllers/public/mapping/types" import generator from "../TestConfiguration/generator" export const generateTable = ( overrides: Partial
= {} ): CreateTableParams => ({ name: generator.word(), - primaryDisplay: "sasa", + primaryDisplay: "testColumn", schema: { "Auto ID": { autocolumn: true, @@ -30,8 +30,8 @@ export const generateTable = ( tableId: "ta_users", type: "link", }, - sasa: { - name: "sasa", + testColumn: { + name: "testColumn", type: "string", }, "Updated At": { @@ -54,7 +54,7 @@ export const generateTable = ( export const generateRow = (overrides: Partial = {}): CreateRowParams => ({ type: "row", tableId: "seed_table", - sasa: generator.word(), + testColumn: generator.word(), relationship: [generator.string({ length: 32, alpha: true, numeric: true })], ...overrides, }) diff --git a/qa-core/src/config/public-api/fixtures/users.ts b/qa-core/src/config/public-api/fixtures/users.ts index aaca5f2480..4aea5333bf 100644 --- a/qa-core/src/config/public-api/fixtures/users.ts +++ b/qa-core/src/config/public-api/fixtures/users.ts @@ -1,7 +1,7 @@ import { CreateUserParams, User, -} from "../../../../../packages/server/src/api/controllers/public/mapping/types" +} from "@budibase/server/api/controllers/public/mapping/types" import generator from "../TestConfiguration/generator" const generate = (overrides: Partial = {}): CreateUserParams => ({ diff --git a/qa-core/src/tests/public-api/applications/applications.spec.ts b/qa-core/src/tests/public-api/applications/applications.spec.ts index 59a24861af..05eaca6177 100644 --- a/qa-core/src/tests/public-api/applications/applications.spec.ts +++ b/qa-core/src/tests/public-api/applications/applications.spec.ts @@ -1,7 +1,7 @@ import TestConfiguration from "../../../config/public-api/TestConfiguration" import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" import generateApp from "../../../config/public-api/fixtures/applications" -import { Application } from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { Application } from "@budibase/server/api/controllers/public/mapping/types" describe("Public API - /applications endpoints", () => { const api = new PublicAPIClient() @@ -20,18 +20,21 @@ describe("Public API - /applications endpoints", () => { it("POST - Create an application", async () => { const [response, app] = await config.applications.create(generateApp()) expect(response).toHaveStatusCode(200) + expect(app._id).toBeDefined() }) it("POST - Search applications", async () => { - const [response, app] = await config.applications.search({ + const [response, apps] = await config.applications.search({ name: config.context.name, }) expect(response).toHaveStatusCode(200) + expect(apps[0]).toEqual(config.context) }) it("GET - Retrieve an application", async () => { const [response, app] = await config.applications.read(config.context._id) expect(response).toHaveStatusCode(200) + expect(app).toEqual(config.context) }) it("PUT - update an application", async () => { @@ -41,5 +44,7 @@ describe("Public API - /applications endpoints", () => { config.context ) expect(response).toHaveStatusCode(200) + expect(app.updatedAt).not.toEqual(config.context.updatedAt) + expect(app.name).toEqual(config.context.name) }) }) diff --git a/qa-core/src/tests/public-api/tables/rows.spec.ts b/qa-core/src/tests/public-api/tables/rows.spec.ts index f34c4cde29..91df85e65c 100644 --- a/qa-core/src/tests/public-api/tables/rows.spec.ts +++ b/qa-core/src/tests/public-api/tables/rows.spec.ts @@ -1,4 +1,4 @@ -import { Row } from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { Row } from "@budibase/server/api/controllers/public/mapping/types" import { generateRow } from "../../../config/public-api/fixtures/tables" import TestConfiguration from "../../../config/public-api/TestConfiguration" import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" @@ -10,15 +10,15 @@ describe("Public API - /rows endpoints", () => { beforeAll(async () => { await config.beforeAll() - const [appResp, app] = await config.applications.seed() + const [aResp, app] = await config.applications.seed() config.tables.api.appId = app._id config.rows.api.appId = app._id - const [tableResp, table] = await config.tables.seed() + const [tResp, table] = await config.tables.seed() config.rows.tableId = table._id - const [response, row] = await config.rows.create(generateRow()) + const [rResp, row] = await config.rows.seed(table._id) config.context = row }) @@ -29,26 +29,37 @@ describe("Public API - /rows endpoints", () => { it("POST - Create a row", async () => { const [response, row] = await config.rows.create(generateRow()) expect(response).toHaveStatusCode(200) + expect(row._id).toBeDefined() }) it("POST - Search rows", async () => { - const [response, row] = await config.rows.search({ - name: config.context.name as string, + const [response, rows] = await config.rows.search({ + query: { + string: { + testColumn: config.context.testColumn as string, + }, + }, }) expect(response).toHaveStatusCode(200) + expect(rows[0]._id).toEqual(config.context._id) + expect(rows[0].tableId).toEqual(config.context.tableId) + expect(rows[0].testColumn).toEqual(config.context.testColumn) }) it("GET - Retrieve a row", async () => { const [response, row] = await config.rows.read(config.context._id) expect(response).toHaveStatusCode(200) + expect(row._id).toEqual(config.context._id) + expect(row.tableId).toEqual(config.context.tableId) }) it("PUT - update a row", async () => { - config.context.name = "UpdatedName" + config.context.testColumn = "UpdatedName" const [response, row] = await config.rows.update( config.context._id, config.context ) expect(response).toHaveStatusCode(200) + expect(row.testColumn).toEqual(config.context.testColumn) }) }) diff --git a/qa-core/src/tests/public-api/tables/tables.spec.ts b/qa-core/src/tests/public-api/tables/tables.spec.ts index c2f50d3e8e..de1ce142ce 100644 --- a/qa-core/src/tests/public-api/tables/tables.spec.ts +++ b/qa-core/src/tests/public-api/tables/tables.spec.ts @@ -1,4 +1,4 @@ -import { Table } from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { Table } from "@budibase/server/api/controllers/public/mapping/types" import { generateTable } from "../../../config/public-api/fixtures/tables" import TestConfiguration from "../../../config/public-api/TestConfiguration" import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" @@ -23,18 +23,21 @@ describe("Public API - /tables endpoints", () => { it("POST - Create a table", async () => { const [response, table] = await config.tables.create(generateTable()) expect(response).toHaveStatusCode(200) + expect(table._id).toBeDefined() }) it("POST - Search tables", async () => { - const [response, table] = await config.tables.search({ + const [response, tables] = await config.tables.search({ name: config.context.name, }) expect(response).toHaveStatusCode(200) + expect(tables[0]).toEqual(config.context) }) it("GET - Retrieve a table", async () => { const [response, table] = await config.tables.read(config.context._id) expect(response).toHaveStatusCode(200) + expect(table).toEqual(config.context) }) it("PUT - update a table", async () => { @@ -44,5 +47,6 @@ describe("Public API - /tables endpoints", () => { config.context ) expect(response).toHaveStatusCode(200) + expect(table).toEqual(config.context) }) }) diff --git a/qa-core/src/tests/public-api/users/users.spec.ts b/qa-core/src/tests/public-api/users/users.spec.ts index b981deb786..5e68c77c50 100644 --- a/qa-core/src/tests/public-api/users/users.spec.ts +++ b/qa-core/src/tests/public-api/users/users.spec.ts @@ -1,7 +1,7 @@ import TestConfiguration from "../../../config/public-api/TestConfiguration" import PublicAPIClient from "../../../config/public-api/TestConfiguration/PublicAPIClient" import generateUser from "../../../config/public-api/fixtures/users" -import { User } from "../../../../../packages/server/src/api/controllers/public/mapping/types" +import { User } from "@budibase/server/api/controllers/public/mapping/types" describe("Public API - /users endpoints", () => { const api = new PublicAPIClient() @@ -9,7 +9,7 @@ describe("Public API - /users endpoints", () => { beforeAll(async () => { await config.beforeAll() - const [response, user] = await config.users.seed() + const [_, user] = await config.users.seed() config.context = user }) @@ -20,18 +20,21 @@ describe("Public API - /users endpoints", () => { it("POST - Create a user", async () => { const [response, user] = await config.users.create(generateUser()) expect(response).toHaveStatusCode(200) + expect(user._id).toBeDefined() }) it("POST - Search users", async () => { - const [response, user] = await config.users.search({ + const [response, users] = await config.users.search({ name: config.context.email, }) expect(response).toHaveStatusCode(200) + expect(users[0]).toEqual(config.context) }) it("GET - Retrieve a user", async () => { const [response, user] = await config.users.read(config.context._id) expect(response).toHaveStatusCode(200) + expect(user).toEqual(config.context) }) it("PUT - update a user", async () => { @@ -41,5 +44,6 @@ describe("Public API - /users endpoints", () => { config.context ) expect(response).toHaveStatusCode(200) + expect(user).toEqual(config.context) }) }) diff --git a/qa-core/tsconfig.json b/qa-core/tsconfig.json index 0fa56727b8..b5f3f25fdd 100644 --- a/qa-core/tsconfig.json +++ b/qa-core/tsconfig.json @@ -14,6 +14,7 @@ "skipLibCheck": true, "paths": { "@budibase/types": ["../packages/types/src"], + "@budibase/server/*": ["../packages/server/src/*"], } }, "ts-node": { From 39ceedc87c03fb59706a8e6b9c02663592a33409 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 15 Sep 2022 20:09:23 +0100 Subject: [PATCH 6/8] tidy up --- .github/workflows/budibase_ci.yml | 10 +++++----- .gitignore | 1 + packages/builder/cypress/setup.js | 6 ------ qa-core/package.json | 5 +++-- .../TestConfiguration/PublicAPIClient.ts | 2 -- qa-core/yarn.lock | 15 ++++++++++++++- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 3715979922..42a0c0a273 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -54,11 +54,11 @@ jobs: verbose: true # TODO: parallelise this - # - name: Cypress run - # uses: cypress-io/github-action@v2 - # with: - # install: false - # command: yarn test:e2e:ci + - name: Cypress run + uses: cypress-io/github-action@v2 + with: + install: false + command: yarn test:e2e:ci - name: QA Core Integration Tests run: | diff --git a/.gitignore b/.gitignore index 32c6faf980..e1d3e6db0e 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,7 @@ typings/ # dotenv environment variables file .env +!qa-core/.env !hosting/.env hosting/.generated-nginx.dev.conf hosting/proxy/.generated-nginx.prod.conf diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index 853cdfc14d..d858801990 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -22,12 +22,6 @@ process.env.COUCH_DB_PASSWORD = "budibase" process.env.INTERNAL_API_KEY = "budibase" process.env.ALLOW_DEV_AUTOMATIONS = 1 -// TODO: inject at the qa-core level -process.env.BB_ADMIN_USER_EMAIL = "qa@budibase.com" -process.env.BB_ADMIN_USER_PASSWORD = "budibase" -process.env.ENCRYPTED_TEST_PUBLIC_API_KEY = - "a65722f06bee5caeadc5d7ca2f543a43-d610e627344210c643bb726f" - // Stop info logs polluting test outputs process.env.LOG_LEVEL = "error" diff --git a/qa-core/package.json b/qa-core/package.json index f82849c92e..b2c3f464d7 100644 --- a/qa-core/package.json +++ b/qa-core/package.json @@ -12,8 +12,8 @@ "test": "jest --runInBand", "test:watch": "jest --watch", "test:debug": "DEBUG=1 jest", - "api:server:setup": "ts-node ../packages/builder/cypress/ts/setup.ts", - "api:server:setup:ci": "node ../packages/builder/cypress/setup.js", + "api:server:setup": "env-cmd ts-node ../packages/builder/cypress/ts/setup.ts", + "api:server:setup:ci": "env-cmd node ../packages/builder/cypress/setup.js", "api:test:ci": "start-server-and-test api:server:setup:ci http://localhost:4100/builder test", "api:test": "start-server-and-test api:server:setup http://localhost:4100/builder test" }, @@ -36,6 +36,7 @@ "@types/jest": "29.0.0", "@types/node-fetch": "2.6.2", "chance": "1.1.8", + "env-cmd": "^10.1.0", "jest": "28.0.2", "prettier": "2.7.1", "start-server-and-test": "1.14.0", diff --git a/qa-core/src/config/public-api/TestConfiguration/PublicAPIClient.ts b/qa-core/src/config/public-api/TestConfiguration/PublicAPIClient.ts index 405007b5aa..3721e31da3 100644 --- a/qa-core/src/config/public-api/TestConfiguration/PublicAPIClient.ts +++ b/qa-core/src/config/public-api/TestConfiguration/PublicAPIClient.ts @@ -38,8 +38,6 @@ class PublicAPIClient { Accept: "application/json", ...options.headers, }, - // TODO: See if this is necessary - credentials: "include", } // @ts-ignore diff --git a/qa-core/yarn.lock b/qa-core/yarn.lock index 9474c47b7c..be9dd3c759 100644 --- a/qa-core/yarn.lock +++ b/qa-core/yarn.lock @@ -1054,6 +1054,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1071,7 +1076,7 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1149,6 +1154,14 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +env-cmd@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/env-cmd/-/env-cmd-10.1.0.tgz#c7f5d3b550c9519f137fdac4dd8fb6866a8c8c4b" + integrity sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA== + dependencies: + commander "^4.0.0" + cross-spawn "^7.0.0" + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" From c368f792693be7ecf48ed6d8c81f39af61b8c882 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 15 Sep 2022 20:12:32 +0100 Subject: [PATCH 7/8] Create .env --- qa-core/.env | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 qa-core/.env diff --git a/qa-core/.env b/qa-core/.env new file mode 100644 index 0000000000..740b1b2b2a --- /dev/null +++ b/qa-core/.env @@ -0,0 +1,3 @@ +BB_ADMIN_USER_EMAIL=qa@budibase.com +BB_ADMIN_USER_PASSWORD=budibase +ENCRYPTED_TEST_PUBLIC_API_KEY=a65722f06bee5caeadc5d7ca2f543a43-d610e627344210c643bb726f From e16560e7689a373b0bf33d3c4adf419583e986b4 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 15 Sep 2022 20:34:37 +0100 Subject: [PATCH 8/8] more random test data for rows --- qa-core/src/config/public-api/fixtures/tables.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa-core/src/config/public-api/fixtures/tables.ts b/qa-core/src/config/public-api/fixtures/tables.ts index cf76855439..d36d7e6db7 100644 --- a/qa-core/src/config/public-api/fixtures/tables.ts +++ b/qa-core/src/config/public-api/fixtures/tables.ts @@ -54,7 +54,7 @@ export const generateTable = ( export const generateRow = (overrides: Partial = {}): CreateRowParams => ({ type: "row", tableId: "seed_table", - testColumn: generator.word(), + testColumn: generator.string({ length: 32, alpha: true, numeric: true }), relationship: [generator.string({ length: 32, alpha: true, numeric: true })], ...overrides, })