diff --git a/packages/server/__mocks__/mysql2.ts b/packages/server/__mocks__/mysql2.ts deleted file mode 100644 index 67ff897811..0000000000 --- a/packages/server/__mocks__/mysql2.ts +++ /dev/null @@ -1,11 +0,0 @@ -const client = { - connect: jest.fn(), - query: jest.fn((query, bindings, fn) => { - fn(null, []) - }), -} - -module.exports = { - createConnection: jest.fn(() => client), - client, -} diff --git a/packages/server/__mocks__/mysql2/promise.ts b/packages/server/__mocks__/mysql2/promise.ts deleted file mode 100644 index f8a4c7b2d6..0000000000 --- a/packages/server/__mocks__/mysql2/promise.ts +++ /dev/null @@ -1,18 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -module MySQLMock { - const mysql: any = {} - - const client = { - connect: jest.fn(), - end: jest.fn(), - query: jest.fn(async () => { - return [[]] - }), - } - - mysql.createConnection = jest.fn(async () => { - return client - }) - - module.exports = mysql -} diff --git a/packages/server/src/api/routes/tests/debug.spec.ts b/packages/server/src/api/routes/tests/debug.spec.ts index 53e1f67823..546344a646 100644 --- a/packages/server/src/api/routes/tests/debug.spec.ts +++ b/packages/server/src/api/routes/tests/debug.spec.ts @@ -1,13 +1,5 @@ -const { checkBuilderEndpoint } = require("./utilities/TestFunctions") -const setup = require("./utilities") - -import os from "os" - -jest.mock("process", () => ({ - arch: "arm64", - version: "v14.20.1", - platform: "darwin", -})) +import * as setup from "./utilities" +import { checkBuilderEndpoint } from "./utilities/TestFunctions" describe("/component", () => { let request = setup.getRequest() @@ -17,21 +9,6 @@ describe("/component", () => { beforeAll(async () => { await config.init() - os.cpus = () => [ - { - model: "test", - speed: 12323, - times: { - user: 0, - nice: 0, - sys: 0, - idle: 0, - irq: 0, - }, - }, - ] - os.uptime = () => 123123123123 - os.totalmem = () => 10000000000 }) describe("/api/debug", () => { @@ -43,14 +20,16 @@ describe("/component", () => { .expect(200) expect(res.body).toEqual({ budibaseVersion: "0.0.0+jest", - cpuArch: "arm64", - cpuCores: 1, - cpuInfo: "test", + cpuArch: expect.any(String), + cpuCores: expect.any(Number), + cpuInfo: expect.any(String), hosting: "docker-compose", - nodeVersion: "v14.20.1", - platform: "darwin", - totalMemory: "9.313225746154785GB", - uptime: "1425036 day(s), 3 hour(s), 32 minute(s)", + nodeVersion: expect.stringMatching(/^v\d+\.\d+\.\d+$/), + platform: expect.any(String), + totalMemory: expect.stringMatching(/^[0-9\\.]+GB$/), + uptime: expect.stringMatching( + /^\d+ day\(s\), \d+ hour\(s\), \d+ minute\(s\)$/ + ), }) }) diff --git a/packages/server/src/api/routes/tests/queries/mysql.spec.ts b/packages/server/src/api/routes/tests/queries/mysql.spec.ts index 6c97ab5835..d04e53971d 100644 --- a/packages/server/src/api/routes/tests/queries/mysql.spec.ts +++ b/packages/server/src/api/routes/tests/queries/mysql.spec.ts @@ -2,9 +2,7 @@ import { Datasource, Query } from "@budibase/types" import * as setup from "../utilities" import { databaseTestProviders } from "../../../../integrations/tests/utils" import mysql from "mysql2/promise" - -jest.unmock("mysql2") -jest.unmock("mysql2/promise") +import { generator } from "@budibase/backend-core/tests" const createTableSQL = ` CREATE TABLE test_table ( @@ -76,164 +74,306 @@ describe("/queries", () => { }) }) - it("should execute a query", async () => { - const query = await createQuery({ - fields: { - sql: "SELECT * FROM test_table ORDER BY id", - }, + describe("read", () => { + it("should execute a query", async () => { + const query = await createQuery({ + fields: { + sql: "SELECT * FROM test_table ORDER BY id", + }, + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + id: 1, + name: "one", + }, + { + id: 2, + name: "two", + }, + { + id: 3, + name: "three", + }, + { + id: 4, + name: "four", + }, + { + id: 5, + name: "five", + }, + ]) }) - const result = await config.api.query.execute(query._id!) - - expect(result.data).toEqual([ - { - id: 1, - name: "one", - }, - { - id: 2, - name: "two", - }, - { - id: 3, - name: "three", - }, - { - id: 4, - name: "four", - }, - { - id: 5, - name: "five", - }, - ]) - }) - - it("should be able to transform a query", async () => { - const query = await createQuery({ - fields: { - sql: "SELECT * FROM test_table WHERE id = 1", - }, - transformer: ` + it("should be able to transform a query", async () => { + const query = await createQuery({ + fields: { + sql: "SELECT * FROM test_table WHERE id = 1", + }, + transformer: ` data[0].id = data[0].id + 1; return data; `, + }) + + const result = await config.api.query.execute(query._id!) + + expect(result.data).toEqual([ + { + id: 2, + name: "one", + }, + ]) }) - const result = await config.api.query.execute(query._id!) + it("should coerce numeric bindings", async () => { + const query = await createQuery({ + fields: { + sql: "SELECT * FROM test_table WHERE id = {{ id }}", + }, + parameters: [ + { + name: "id", + default: "", + }, + ], + }) - expect(result.data).toEqual([ - { - id: 2, - name: "one", - }, - ]) + const result = await config.api.query.execute(query._id!, { + parameters: { + id: "1", + }, + }) + + expect(result.data).toEqual([ + { + id: 1, + name: "one", + }, + ]) + }) }) - it("should be able to insert with bindings", async () => { - const query = await createQuery({ - fields: { - sql: "INSERT INTO test_table (name) VALUES ({{ foo }})", - }, - parameters: [ + describe("create", () => { + it("should be able to insert with bindings", async () => { + const query = await createQuery({ + fields: { + sql: "INSERT INTO test_table (name) VALUES ({{ foo }})", + }, + parameters: [ + { + name: "foo", + default: "bar", + }, + ], + queryVerb: "create", + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { + foo: "baz", + }, + }) + + expect(result.data).toEqual([ { + created: true, + }, + ]) + + await withConnection(async connection => { + const [rows] = await connection.query( + "SELECT * FROM test_table WHERE name = 'baz'" + ) + expect(rows).toHaveLength(1) + }) + }) + + it.each(["2021-02-05T12:01:00.000Z", "2021-02-05"])( + "should coerce %s into a date", + async dateStr => { + const date = new Date(dateStr) + const tableName = `\`${generator.guid()}\`` + await withConnection(async connection => { + await connection.query(`CREATE TABLE ${tableName} ( + id INT AUTO_INCREMENT PRIMARY KEY, + date DATETIME NOT NULL + )`) + }) + + const query = await createQuery({ + fields: { + sql: `INSERT INTO ${tableName} (date) VALUES ({{ date }})`, + }, + parameters: [ + { + name: "date", + default: "", + }, + ], + queryVerb: "create", + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { date: dateStr }, + }) + + expect(result.data).toEqual([{ created: true }]) + + await withConnection(async connection => { + const [rows] = await connection.query( + `SELECT * FROM ${tableName} WHERE date = '${date.toISOString()}'` + ) + expect(rows).toHaveLength(1) + }) + } + ) + + it.each(["2021,02,05", "202205-1500"])( + "should not coerce %s as a date", + async date => { + const query = await createQuery({ + fields: { + sql: "INSERT INTO test_table (name) VALUES ({{ name }})", + }, + parameters: [ + { + name: "name", + default: "", + }, + ], + queryVerb: "create", + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { + name: date, + }, + }) + + expect(result.data).toEqual([{ created: true }]) + + await withConnection(async connection => { + const [rows] = await connection.query( + `SELECT * FROM test_table WHERE name = '${date}'` + ) + expect(rows).toHaveLength(1) + }) + } + ) + }) + + describe("update", () => { + it("should be able to update rows", async () => { + const query = await createQuery({ + fields: { + sql: "UPDATE test_table SET name = {{ name }} WHERE id = {{ id }}", + }, + parameters: [ + { + name: "id", + default: "", + }, + { + name: "name", + default: "updated", + }, + ], + queryVerb: "update", + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { + id: "1", name: "foo", - default: "bar", }, - ], - queryVerb: "create", + }) + + expect(result.data).toEqual([ + { + updated: true, + }, + ]) + + await withConnection(async connection => { + const [rows] = await connection.query( + "SELECT * FROM test_table WHERE id = 1" + ) + expect(rows).toEqual([{ id: 1, name: "foo" }]) + }) }) - const result = await config.api.query.execute(query._id!, { - parameters: { - foo: "baz", - }, - }) + it("should be able to execute an update that updates no rows", async () => { + const query = await createQuery({ + fields: { + sql: "UPDATE test_table SET name = 'updated' WHERE id = 100", + }, + queryVerb: "update", + }) - expect(result.data).toEqual([ - { - created: true, - }, - ]) + const result = await config.api.query.execute(query._id!) - await withConnection(async connection => { - const [rows] = await connection.query( - "SELECT * FROM test_table WHERE name = 'baz'" - ) - expect(rows).toHaveLength(1) + expect(result.data).toEqual([ + { + updated: true, + }, + ]) }) }) - it("should be able to update rows", async () => { - const query = await createQuery({ - fields: { - sql: "UPDATE test_table SET name = {{ name }} WHERE id = {{ id }}", - }, - parameters: [ - { - name: "id", - default: "", + describe("delete", () => { + it("should be able to delete rows", async () => { + const query = await createQuery({ + fields: { + sql: "DELETE FROM test_table WHERE id = {{ id }}", }, - { - name: "name", - default: "updated", + parameters: [ + { + name: "id", + default: "", + }, + ], + queryVerb: "delete", + }) + + const result = await config.api.query.execute(query._id!, { + parameters: { + id: "1", }, - ], - queryVerb: "update", - }) + }) - const result = await config.api.query.execute(query._id!, { - parameters: { - id: "1", - name: "foo", - }, - }) - - expect(result.data).toEqual([ - { - updated: true, - }, - ]) - - await withConnection(async connection => { - const [rows] = await connection.query( - "SELECT * FROM test_table WHERE id = 1" - ) - expect(rows).toEqual([{ id: 1, name: "foo" }]) - }) - }) - - it("should be able to delete rows", async () => { - const query = await createQuery({ - fields: { - sql: "DELETE FROM test_table WHERE id = {{ id }}", - }, - parameters: [ + expect(result.data).toEqual([ { - name: "id", - default: "", + deleted: true, }, - ], - queryVerb: "delete", + ]) + + await withConnection(async connection => { + const [rows] = await connection.query( + "SELECT * FROM test_table WHERE id = 1" + ) + expect(rows).toHaveLength(0) + }) }) - const result = await config.api.query.execute(query._id!, { - parameters: { - id: "1", - }, - }) + it("should be able to execute a delete that deletes no rows", async () => { + const query = await createQuery({ + fields: { + sql: "DELETE FROM test_table WHERE id = 100", + }, + queryVerb: "delete", + }) - expect(result.data).toEqual([ - { - deleted: true, - }, - ]) + const result = await config.api.query.execute(query._id!) - await withConnection(async connection => { - const [rows] = await connection.query( - "SELECT * FROM test_table WHERE id = 1" - ) - expect(rows).toHaveLength(0) + expect(result.data).toEqual([ + { + deleted: true, + }, + ]) }) }) }) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 854410dcf6..4d46bbe2a9 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -39,8 +39,6 @@ import * as uuid from "uuid" const timestamp = new Date("2023-01-26T11:48:57.597Z").toISOString() tk.freeze(timestamp) -jest.unmock("mysql2") -jest.unmock("mysql2/promise") jest.unmock("mssql") jest.unmock("pg") diff --git a/packages/server/src/api/routes/tests/viewV2.spec.ts b/packages/server/src/api/routes/tests/viewV2.spec.ts index ded5e08d29..8652778467 100644 --- a/packages/server/src/api/routes/tests/viewV2.spec.ts +++ b/packages/server/src/api/routes/tests/viewV2.spec.ts @@ -20,8 +20,6 @@ import * as uuid from "uuid" import { databaseTestProviders } from "../../../integrations/tests/utils" import merge from "lodash/merge" -jest.unmock("mysql2") -jest.unmock("mysql2/promise") jest.unmock("mssql") jest.unmock("pg") diff --git a/packages/server/src/integration-test/mysql.spec.ts b/packages/server/src/integration-test/mysql.spec.ts index a22410b812..92420fb336 100644 --- a/packages/server/src/integration-test/mysql.spec.ts +++ b/packages/server/src/integration-test/mysql.spec.ts @@ -20,7 +20,6 @@ fetch.mockSearch() const config = setup.getConfig()! -jest.unmock("mysql2/promise") jest.mock("../websockets", () => ({ clientAppSocket: jest.fn(), gridAppSocket: jest.fn(), diff --git a/packages/server/src/integrations/tests/mysql.spec.ts b/packages/server/src/integrations/tests/mysql.spec.ts deleted file mode 100644 index 5180645885..0000000000 --- a/packages/server/src/integrations/tests/mysql.spec.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { default as MySQLIntegration, bindingTypeCoerce } from "../mysql" - -jest.mock("mysql2") - -class TestConfiguration { - integration: any - - constructor(config: any = { ssl: {} }) { - this.integration = new MySQLIntegration.integration(config) - } -} - -describe("MySQL Integration", () => { - let config: any - - beforeEach(() => { - config = new TestConfiguration() - }) - - it("calls the create method with the correct params", async () => { - const sql = "insert into users (name, age) values ('Joe', 123);" - await config.integration.create({ - sql, - }) - expect(config.integration.client.query).toHaveBeenCalledWith(sql, []) - }) - - it("calls the read method with the correct params", async () => { - const sql = "select * from users;" - await config.integration.read({ - sql, - }) - expect(config.integration.client.query).toHaveBeenCalledWith(sql, []) - }) - - it("calls the update method with the correct params", async () => { - const sql = "update table users set name = 'test';" - await config.integration.update({ - sql, - }) - expect(config.integration.client.query).toHaveBeenCalledWith(sql, []) - }) - - it("calls the delete method with the correct params", async () => { - const sql = "delete from users where name = 'todelete';" - await config.integration.delete({ - sql, - }) - expect(config.integration.client.query).toHaveBeenCalledWith(sql, []) - }) - - describe("no rows returned", () => { - it("returns the correct response when the create response has no rows", async () => { - const sql = "insert into users (name, age) values ('Joe', 123);" - const response = await config.integration.create({ - sql, - }) - expect(response).toEqual([{ created: true }]) - }) - - it("returns the correct response when the update response has no rows", async () => { - const sql = "update table users set name = 'test';" - const response = await config.integration.update({ - sql, - }) - expect(response).toEqual([{ updated: true }]) - }) - - it("returns the correct response when the delete response has no rows", async () => { - const sql = "delete from users where name = 'todelete';" - const response = await config.integration.delete({ - sql, - }) - expect(response).toEqual([{ deleted: true }]) - }) - }) - - describe("binding type coerce", () => { - it("ignores non-string types", async () => { - const sql = "select * from users;" - const date = new Date() - await config.integration.read({ - sql, - bindings: [11, date, ["a", "b", "c"], { id: 1 }], - }) - expect(config.integration.client.query).toHaveBeenCalledWith(sql, [ - 11, - date, - ["a", "b", "c"], - { id: 1 }, - ]) - }) - - it("parses strings matching a number regex", async () => { - const sql = "select * from users;" - await config.integration.read({ - sql, - bindings: ["101", "3.14"], - }) - expect(config.integration.client.query).toHaveBeenCalledWith( - sql, - [101, 3.14] - ) - }) - - it("parses strings matching a valid date format", async () => { - const sql = "select * from users;" - await config.integration.read({ - sql, - bindings: [ - "2001-10-30", - "2010-09-01T13:30:59.123Z", - "2021-02-05 12:01 PM", - ], - }) - expect(config.integration.client.query).toHaveBeenCalledWith(sql, [ - new Date("2001-10-30T00:00:00.000Z"), - new Date("2010-09-01T13:30:59.123Z"), - new Date("2021-02-05T12:01:00.000Z"), - ]) - }) - - it("does not parse string matching a valid array of numbers as date", async () => { - const sql = "select * from users;" - await config.integration.read({ - sql, - bindings: ["1,2,2017"], - }) - expect(config.integration.client.query).toHaveBeenCalledWith(sql, [ - "1,2,2017", - ]) - }) - }) -}) - -describe("bindingTypeCoercion", () => { - it("shouldn't coerce something that looks like a date", () => { - const response = bindingTypeCoerce(["202205-1500"]) - expect(response[0]).toBe("202205-1500") - }) - - it("should coerce an actual date", () => { - const date = new Date("2023-06-13T14:24:22.620Z") - const response = bindingTypeCoerce(["2023-06-13T14:24:22.620Z"]) - expect(response[0]).toEqual(date) - }) - - it("should coerce numbers", () => { - const response = bindingTypeCoerce(["0"]) - expect(response[0]).toEqual(0) - }) -}) diff --git a/packages/server/src/sdk/app/rows/search/tests/external.spec.ts b/packages/server/src/sdk/app/rows/search/tests/external.spec.ts index bae84592ca..8ecec784dd 100644 --- a/packages/server/src/sdk/app/rows/search/tests/external.spec.ts +++ b/packages/server/src/sdk/app/rows/search/tests/external.spec.ts @@ -17,8 +17,6 @@ import { generator, } from "@budibase/backend-core/tests" -jest.unmock("mysql2/promise") - jest.setTimeout(30000) describe("external search", () => { diff --git a/qa-core/src/integrations/external-schema/mysql.integration.spec.ts b/qa-core/src/integrations/external-schema/mysql.integration.spec.ts index c34651ea0e..5a7e1989d2 100644 --- a/qa-core/src/integrations/external-schema/mysql.integration.spec.ts +++ b/qa-core/src/integrations/external-schema/mysql.integration.spec.ts @@ -1,8 +1,6 @@ import { GenericContainer } from "testcontainers" import mysql from "../../../../packages/server/src/integrations/mysql" -jest.unmock("mysql2/promise") - describe("datasource validators", () => { describe("mysql", () => { let config: any diff --git a/qa-core/src/integrations/validators/mysql.integration.spec.ts b/qa-core/src/integrations/validators/mysql.integration.spec.ts index 0f0de132fe..e828d192af 100644 --- a/qa-core/src/integrations/validators/mysql.integration.spec.ts +++ b/qa-core/src/integrations/validators/mysql.integration.spec.ts @@ -1,8 +1,6 @@ import { GenericContainer } from "testcontainers" import mysql from "../../../../packages/server/src/integrations/mysql" -jest.unmock("mysql2/promise") - describe("datasource validators", () => { describe("mysql", () => { let host: string