diff --git a/eslint.config.mjs b/eslint.config.mjs index 59c2202e94..2d2385cbdb 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -6,6 +6,7 @@ import tsParser from "@typescript-eslint/parser" import eslintPluginJest from "eslint-plugin-jest" import eslintPluginSvelte from "eslint-plugin-svelte" import eslintPluginLocalRules from "eslint-plugin-local-rules" +import eslintPluginVitest from "@vitest/eslint-plugin" import eslint from "@eslint/js" import tseslint from "typescript-eslint" @@ -17,17 +18,10 @@ export default [ "**/node_modules", "**/dist", "**/public", - "**/*.spec.js", "**/bundle.js", - "**/node_modules", - "**/public", - "**/dist", + "**/coverage", "packages/server/builder", - "packages/server/coverage", - "packages/worker/coverage", - "packages/backend-core/coverage", "packages/server/client", - "packages/server/coverage", "packages/builder/.routify", "packages/sdk/sdk", "**/*.ivm.bundle.js", @@ -102,18 +96,12 @@ export default [ }, rules: { - "prefer-spread": "off", - "no-unused-vars": "off", - "prefer-rest-params": "off", "local-rules/no-barrel-imports": "error", "local-rules/no-budibase-imports": "error", "local-rules/no-console-error": "error", - "@typescript-eslint/no-this-alias": "off", - "@typescript-eslint/no-unused-expressions": "off", - "@typescript-eslint/no-empty-object-type": "off", - "@typescript-eslint/no-require-imports": "off", - "@typescript-eslint/ban-ts-comment": "off", + // @typscript-eslint/no-unused-vars supersedes no-unused-vars + "no-unused-vars": "off", "@typescript-eslint/no-unused-vars": [ "error", { @@ -125,22 +113,28 @@ export default [ }, ], + // @typescript-eslint/no-redeclare supersedes no-redeclare "no-redeclare": "off", "@typescript-eslint/no-redeclare": "error", + + // @typescript-eslint/no-dupe-class-members supersedes no-dupe-class-members "no-dupe-class-members": "off", + "@typescript-eslint/no-dupe-class-members": "error", }, } }), { - files: ["**/*.spec.ts"], + files: ["**/*.spec.ts", "**/*.spec.js"], plugins: { jest: eslintPluginJest, + vitest: eslintPluginVitest, }, languageOptions: { globals: { ...eslintPluginJest.environments.globals.globals, + ...eslintPluginVitest.environments.env.globals, NodeJS: true, }, @@ -148,13 +142,20 @@ export default [ }, rules: { - "local-rules/no-test-com": "error", - "local-rules/email-domain-example-com": "error", + ...eslintPluginVitest.configs.recommended.rules, + ...eslintPluginJest.configs.recommended.rules, + "no-console": "warn", + + "vitest/expect-expect": "off", + "jest/expect-expect": "off", "jest/no-conditional-expect": "off", - "no-dupe-class-members": "off", - "no-redeclare": "off", + "jest/no-disabled-tests": "off", + "jest/no-standalone-expect": "off", + + "local-rules/no-test-com": "error", + "local-rules/email-domain-example-com": "error", }, }, { diff --git a/hosting/scripts/setup.js b/hosting/scripts/setup.js index c62ac14f29..35ee32bd64 100755 --- a/hosting/scripts/setup.js +++ b/hosting/scripts/setup.js @@ -2,7 +2,6 @@ const os = require("os") const exec = require("child_process").exec -const fs = require("fs") const platform = os.platform() const windows = platform === "win32" @@ -17,10 +16,11 @@ function execute(command) { async function commandExistsUnix(command) { const unixCmd = `command -v ${command} 2>/dev/null && { echo >&1 ${command}; exit 0; }` - return execute(command) + return execute(unixCmd) } async function commandExistsWindows(command) { + // eslint-disable-next-line no-control-regex if (/[\x00-\x1f<>:"|?*]/.test(command)) { return false } diff --git a/package.json b/package.json index f95685c6ff..b047d25461 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "@types/node": "20.10.0", "@types/proper-lockfile": "^4.1.4", "@typescript-eslint/parser": "8.17.0", + "@vitest/eslint-plugin": "^1.1.14", "cross-spawn": "7.0.6", "depcheck": "^1.4.7", "esbuild": "^0.18.17", diff --git a/packages/backend-core/tests/core/users/users.spec.js b/packages/backend-core/tests/core/users/users.spec.js index f08c435b95..dde0d87fb7 100644 --- a/packages/backend-core/tests/core/users/users.spec.js +++ b/packages/backend-core/tests/core/users/users.spec.js @@ -11,15 +11,15 @@ const { getCreatorCount } = require("../../../src/users/users") describe("Users", () => { let getGlobalDBMock - let getGlobalUserParamsMock let paginationMock beforeEach(() => { jest.resetAllMocks() getGlobalDBMock = jest.spyOn(context, "getGlobalDB") - getGlobalUserParamsMock = jest.spyOn(db, "getGlobalUserParams") paginationMock = jest.spyOn(db, "pagination") + + jest.spyOn(db, "getGlobalUserParams") }) it("Retrieves the number of creators", async () => { diff --git a/packages/server/src/api/controllers/query/import/tests/index.spec.js b/packages/server/src/api/controllers/query/import/tests/index.spec.js index fcbd4509ee..409a55e81b 100644 --- a/packages/server/src/api/controllers/query/import/tests/index.spec.js +++ b/packages/server/src/api/controllers/query/import/tests/index.spec.js @@ -111,8 +111,8 @@ describe("Rest Importer", () => { const importResult = await restImporter.importQueries(datasource._id) expect(importResult.errorQueries.length).toBe(0) expect(importResult.queries.length).toBe(assertions[key].count) - expect(events.query.imported).toBeCalledTimes(1) - expect(events.query.imported).toBeCalledWith( + expect(events.query.imported).toHaveBeenCalledTimes(1) + expect(events.query.imported).toHaveBeenCalledWith( datasource, assertions[key].source, assertions[key].count diff --git a/packages/server/src/api/routes/tests/analytics.spec.js b/packages/server/src/api/routes/tests/analytics.spec.js index c69307656d..0b947ebcd9 100644 --- a/packages/server/src/api/routes/tests/analytics.spec.js +++ b/packages/server/src/api/routes/tests/analytics.spec.js @@ -4,14 +4,13 @@ const { events, constants } = require("@budibase/backend-core") describe("/static", () => { let request = setup.getRequest() let config = setup.getConfig() - let app const timezone = "Europe/London" afterAll(setup.afterAll) beforeAll(async () => { - app = await config.init() + await config.init() }) beforeEach(() => { @@ -26,10 +25,10 @@ describe("/static", () => { .set(config.defaultHeaders()) .expect(200) - expect(events.serve.servedBuilder).toBeCalledTimes(1) - expect(events.serve.servedBuilder).toBeCalledWith(timezone) - expect(events.serve.servedApp).not.toBeCalled() - expect(events.serve.servedAppPreview).not.toBeCalled() + expect(events.serve.servedBuilder).toHaveBeenCalledTimes(1) + expect(events.serve.servedBuilder).toHaveBeenCalledWith(timezone) + expect(events.serve.servedApp).not.toHaveBeenCalled() + expect(events.serve.servedAppPreview).not.toHaveBeenCalled() }) it("should ping from app preview", async () => { @@ -39,12 +38,12 @@ describe("/static", () => { .set(config.defaultHeaders()) .expect(200) - expect(events.serve.servedAppPreview).toBeCalledTimes(1) - expect(events.serve.servedAppPreview).toBeCalledWith( + expect(events.serve.servedAppPreview).toHaveBeenCalledTimes(1) + expect(events.serve.servedAppPreview).toHaveBeenCalledWith( config.getApp(), timezone ) - expect(events.serve.servedApp).not.toBeCalled() + expect(events.serve.servedApp).not.toHaveBeenCalled() }) it("should ping from app", async () => { @@ -57,13 +56,13 @@ describe("/static", () => { .set(headers) .expect(200) - expect(events.serve.servedApp).toBeCalledTimes(1) - expect(events.serve.servedApp).toBeCalledWith( + expect(events.serve.servedApp).toHaveBeenCalledTimes(1) + expect(events.serve.servedApp).toHaveBeenCalledWith( config.getProdApp(), timezone, undefined ) - expect(events.serve.servedAppPreview).not.toBeCalled() + expect(events.serve.servedAppPreview).not.toHaveBeenCalled() }) it("should ping from an embedded app", async () => { @@ -76,13 +75,13 @@ describe("/static", () => { .set(headers) .expect(200) - expect(events.serve.servedApp).toBeCalledTimes(1) - expect(events.serve.servedApp).toBeCalledWith( + expect(events.serve.servedApp).toHaveBeenCalledTimes(1) + expect(events.serve.servedApp).toHaveBeenCalledWith( config.getProdApp(), timezone, true ) - expect(events.serve.servedAppPreview).not.toBeCalled() + expect(events.serve.servedAppPreview).not.toHaveBeenCalled() }) }) }) diff --git a/packages/server/src/api/routes/tests/dev.spec.js b/packages/server/src/api/routes/tests/dev.spec.js index 73f506d17f..4c999e98c3 100644 --- a/packages/server/src/api/routes/tests/dev.spec.js +++ b/packages/server/src/api/routes/tests/dev.spec.js @@ -19,7 +19,7 @@ describe("/dev", () => { .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) - expect(events.app.reverted).toBeCalledTimes(1) + expect(events.app.reverted).toHaveBeenCalledTimes(1) }) }) @@ -32,8 +32,10 @@ describe("/dev", () => { .expect(200) expect(res.body.version).toBe("0.0.0+jest") - expect(events.installation.versionChecked).toBeCalledTimes(1) - expect(events.installation.versionChecked).toBeCalledWith("0.0.0+jest") + expect(events.installation.versionChecked).toHaveBeenCalledTimes(1) + expect(events.installation.versionChecked).toHaveBeenCalledWith( + "0.0.0+jest" + ) }) }) }) diff --git a/packages/server/src/api/routes/tests/layout.spec.js b/packages/server/src/api/routes/tests/layout.spec.js index c3a3010e32..c5ffeb9c20 100644 --- a/packages/server/src/api/routes/tests/layout.spec.js +++ b/packages/server/src/api/routes/tests/layout.spec.js @@ -25,7 +25,7 @@ describe("/layouts", () => { .expect("Content-Type", /json/) .expect(200) expect(res.body._rev).toBeDefined() - expect(events.layout.created).toBeCalledTimes(1) + expect(events.layout.created).toHaveBeenCalledTimes(1) }) it("should apply authorization to endpoint", async () => { @@ -45,7 +45,7 @@ describe("/layouts", () => { .expect("Content-Type", /json/) .expect(200) expect(res.body.message).toBeDefined() - expect(events.layout.deleted).toBeCalledTimes(1) + expect(events.layout.deleted).toHaveBeenCalledTimes(1) }) it("should apply authorization to endpoint", async () => { diff --git a/packages/server/src/integrations/tests/googlesheets.spec.ts b/packages/server/src/integrations/tests/googlesheets.spec.ts index 2c0e4dce84..966123513c 100644 --- a/packages/server/src/integrations/tests/googlesheets.spec.ts +++ b/packages/server/src/integrations/tests/googlesheets.spec.ts @@ -389,24 +389,24 @@ describe("Google Sheets Integration", () => { }) // TODO: this gets the error "Sheet is not large enough to fit 27 columns. Resize the sheet first." - // it("should be able to add a new column", async () => { - // const updatedTable = await config.api.table.save({ - // ...table, - // schema: { - // ...table.schema, - // newColumn: { - // name: "newColumn", - // type: FieldType.STRING, - // }, - // }, - // }) + it.skip("should be able to add a new column", async () => { + const updatedTable = await config.api.table.save({ + ...table, + schema: { + ...table.schema, + newColumn: { + name: "newColumn", + type: FieldType.STRING, + }, + }, + }) - // expect(updatedTable.schema.newColumn).toBeDefined() + expect(updatedTable.schema.newColumn).toBeDefined() - // expect(mock.cell("A1")).toEqual("name") - // expect(mock.cell("B1")).toEqual("description") - // expect(mock.cell("C1")).toEqual("newColumn") - // }) + expect(mock.cell("A1")).toEqual("name") + expect(mock.cell("B1")).toEqual("description") + expect(mock.cell("C1")).toEqual("newColumn") + }) it("should be able to delete a column", async () => { const row = await config.api.row.save(table._id!, { diff --git a/packages/server/src/integrations/tests/rest.spec.ts b/packages/server/src/integrations/tests/rest.spec.ts index fac6f58c3b..0411a1380e 100644 --- a/packages/server/src/integrations/tests/rest.spec.ts +++ b/packages/server/src/integrations/tests/rest.spec.ts @@ -3,6 +3,8 @@ import { RestIntegration } from "../rest" import { BodyType, RestAuthType } from "@budibase/types" import { Response } from "node-fetch" import TestConfiguration from "../../../src/tests/utilities/TestConfiguration" +import { createServer } from "http" +import { AddressInfo } from "net" const UUID_REGEX = "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}" @@ -455,28 +457,27 @@ describe("REST Integration", () => { // NOTE(samwho): it seems like this code doesn't actually work because it requires // node-fetch >=3, and we're not on that because upgrading to it produces errors to // do with ESM that are above my pay grade. + it.skip("doesn't fail when legacyHttpParser is set", async () => { + const server = createServer((req, res) => { + res.writeHead(200, { + "Transfer-Encoding": "chunked", + "Content-Length": "10", + }) + res.end(JSON.stringify({ foo: "bar" })) + }) - // it("doesn't fail when legacyHttpParser is set", async () => { - // const server = createServer((req, res) => { - // res.writeHead(200, { - // "Transfer-Encoding": "chunked", - // "Content-Length": "10", - // }) - // res.end(JSON.stringify({ foo: "bar" })) - // }) + server.listen() + await new Promise(resolve => server.once("listening", resolve)) - // server.listen() - // await new Promise(resolve => server.once("listening", resolve)) + const address = server.address() as AddressInfo - // const address = server.address() as AddressInfo - - // const integration = new RestIntegration({ - // url: `http://localhost:${address.port}`, - // legacyHttpParser: true, - // }) - // const { data } = await integration.read({}) - // expect(data).toEqual({ foo: "bar" }) - // }) + const integration = new RestIntegration({ + url: `http://localhost:${address.port}`, + legacyHttpParser: true, + }) + const { data } = await integration.read({}) + expect(data).toEqual({ foo: "bar" }) + }) it("doesn't fail when legacyHttpParser is true", async () => { nock("https://example.com").get("/").reply(200, { foo: "bar" }) diff --git a/yarn.lock b/yarn.lock index 4b4ab5146f..1e44ea753a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6432,6 +6432,11 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== +"@vitest/eslint-plugin@^1.1.14": + version "1.1.14" + resolved "https://registry.yarnpkg.com/@vitest/eslint-plugin/-/eslint-plugin-1.1.14.tgz#dc3bb332461282cfab213b76e5e42bd2dad5929b" + integrity sha512-ej0cT5rUt7uvwxuu7Qxkm7fI+eaOq8vD34qGpuRoXCdvOybOlE5GDqtgvVCYbxLANkcRJfm5VDU1TnJmQRHi9g== + "@vitest/expect@0.29.8": version "0.29.8" resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-0.29.8.tgz#6ecdd031b4ea8414717d10b65ccd800908384612"