Add force exit, -e flag and streaming to tests (#10151)

* Add force exit, -e flag and streaming to tests

* Temp remove script usage from worker tests

* Revert "Temp remove script usage from worker tests"

This reverts commit 5e0ed2e92d.

* Always fail test

* Ignore server test package from coverage report

* Unscope server only

* Run all server tests again

* Update backend core test script to fail when any command fails and force exit

* Don't try to require client in test

* Port memory limit fix from develop

* Remove always failing test and commented out block for client require

* Fixing some issues with test cases.

* Revert assertions in internalSearch.spec.js

---------

Co-authored-by: mike12345567 <me@michaeldrury.co.uk>
This commit is contained in:
Rory Powell 2023-03-31 10:32:13 +01:00 committed by GitHub
parent de2aecb11e
commit 79bec7d86d
17 changed files with 133 additions and 95 deletions

View File

@ -44,7 +44,7 @@
"dev": "yarn run kill-all && lerna link && lerna run --parallel dev:builder --concurrency 1", "dev": "yarn run kill-all && lerna link && lerna run --parallel dev:builder --concurrency 1",
"dev:noserver": "yarn run kill-builder && lerna link && lerna run dev:stack:up && lerna run --parallel dev:builder --concurrency 1 --ignore @budibase/backend-core --ignore @budibase/server --ignore @budibase/worker", "dev:noserver": "yarn run kill-builder && lerna link && lerna run dev:stack:up && lerna run --parallel dev:builder --concurrency 1 --ignore @budibase/backend-core --ignore @budibase/server --ignore @budibase/worker",
"dev:server": "yarn run kill-server && lerna run --parallel dev:builder --concurrency 1 --scope @budibase/backend-core --scope @budibase/worker --scope @budibase/server", "dev:server": "yarn run kill-server && lerna run --parallel dev:builder --concurrency 1 --scope @budibase/backend-core --scope @budibase/worker --scope @budibase/server",
"test": "lerna run test", "test": "lerna run test --stream",
"test:pro": "bash scripts/pro/test.sh", "test:pro": "bash scripts/pro/test.sh",
"lint:eslint": "eslint packages && eslint qa-core", "lint:eslint": "eslint packages && eslint qa-core",
"lint:prettier": "prettier --check \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\" && prettier --check \"qa-core/**/*.{js,ts,svelte}\"", "lint:prettier": "prettier --check \"packages/**/*.{js,ts,svelte}\" && prettier --write \"examples/**/*.{js,ts,svelte}\" && prettier --check \"qa-core/**/*.{js,ts,svelte}\"",

View File

@ -1,12 +1,13 @@
#!/bin/bash #!/bin/bash
set -e
if [[ -n $CI ]] if [[ -n $CI ]]
then then
# --runInBand performs better in ci where resources are limited # --runInBand performs better in ci where resources are limited
echo "jest --coverage --runInBand" echo "jest --coverage --runInBand --forceExit"
jest --coverage --runInBand jest --coverage --runInBand --forceExit
else else
# --maxWorkers performs better in development # --maxWorkers performs better in development
echo "jest --coverage" echo "jest --coverage --forceExit"
jest --coverage jest --coverage --forceExit
fi fi

View File

@ -4,3 +4,4 @@ process.env.NODE_ENV = "jest"
process.env.MOCK_REDIS = "1" process.env.MOCK_REDIS = "1"
process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error" process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error"
process.env.ENABLE_4XX_HTTP_LOGGING = "0" process.env.ENABLE_4XX_HTTP_LOGGING = "0"
process.env.REDIS_PASSWORD = "budibase"

View File

@ -4,6 +4,7 @@ module FetchMock {
// @ts-ignore // @ts-ignore
const fetch = jest.requireActual("node-fetch") const fetch = jest.requireActual("node-fetch")
let failCount = 0 let failCount = 0
let mockSearch = false
const func = async (url: any, opts: any) => { const func = async (url: any, opts: any) => {
function json(body: any, status = 200) { function json(body: any, status = 200) {
@ -69,7 +70,7 @@ module FetchMock {
}, },
404 404
) )
} else if (url.includes("_search")) { } else if (mockSearch && url.includes("_search")) {
const body = opts.body const body = opts.body
const parts = body.split("tableId:") const parts = body.split("tableId:")
let tableId let tableId
@ -192,5 +193,9 @@ module FetchMock {
func.Headers = fetch.Headers func.Headers = fetch.Headers
func.mockSearch = () => {
mockSearch = true
}
module.exports = func module.exports = func
} }

View File

@ -43,6 +43,7 @@ const config: Config.InitialOptions = {
"../backend-core/src/**/*.{js,ts}", "../backend-core/src/**/*.{js,ts}",
// The use of coverage with couchdb view functions breaks tests // The use of coverage with couchdb view functions breaks tests
"!src/db/views/staticViews.*", "!src/db/views/staticViews.*",
"!src/tests/**/*.{js,ts}",
], ],
coverageReporters: ["lcov", "json", "clover"], coverageReporters: ["lcov", "json", "clover"],
} }

View File

@ -1,12 +1,14 @@
#!/bin/bash #!/bin/bash
set -e
if [[ -n $CI ]] if [[ -n $CI ]]
then then
# --runInBand performs better in ci where resources are limited # --runInBand performs better in ci where resources are limited
echo "jest --coverage --runInBand" export NODE_OPTIONS="--max-old-space-size=4096"
jest --coverage --runInBand echo "jest --coverage --runInBand --forceExit"
jest --coverage --runInBand --forceExit
else else
# --maxWorkers performs better in development # --maxWorkers performs better in development
echo "jest --coverage --maxWorkers=2" echo "jest --coverage --maxWorkers=2 --forceExit"
jest --coverage --maxWorkers=2 jest --coverage --maxWorkers=2 --forceExit
fi fi

View File

@ -62,10 +62,11 @@ export async function validate({
} }
const errors: any = {} const errors: any = {}
for (let fieldName of Object.keys(fetchedTable.schema)) { for (let fieldName of Object.keys(fetchedTable.schema)) {
const constraints = cloneDeep(fetchedTable.schema[fieldName].constraints) const column = fetchedTable.schema[fieldName]
const type = fetchedTable.schema[fieldName].type const constraints = cloneDeep(column.constraints)
const type = column.type
// formulas shouldn't validated, data will be deleted anyway // formulas shouldn't validated, data will be deleted anyway
if (type === FieldTypes.FORMULA) { if (type === FieldTypes.FORMULA || column.autocolumn) {
continue continue
} }
// special case for options, need to always allow unselected (null) // special case for options, need to always allow unselected (null)

View File

@ -0,0 +1,31 @@
import * as setup from "./utilities"
import { roles, db as dbCore } from "@budibase/backend-core"
describe("/api/applications/:appId/sync", () => {
let request = setup.getRequest()
let config = setup.getConfig()
let app
afterAll(setup.afterAll)
beforeAll(async () => {
app = await config.init()
// create some users which we will use throughout the tests
await config.createUser({
email: "sync1@test.com",
roles: {
[app._id!]: roles.BUILTIN_ROLE_IDS.BASIC,
},
})
})
async function getUserMetadata() {
const { rows } = await config.searchRows(dbCore.InternalTable.USER_METADATA)
return rows
}
it("make sure its empty initially", async () => {
const rows = await getUserMetadata()
expect(rows.length).toBe(1)
})
})

View File

@ -1,6 +1,7 @@
const fetch = require("node-fetch")
fetch.mockSearch()
const search = require("../../controllers/row/internalSearch") const search = require("../../controllers/row/internalSearch")
// this will be mocked out for _search endpoint // this will be mocked out for _search endpoint
const fetch = require("node-fetch")
const PARAMS = { const PARAMS = {
tableId: "ta_12345679abcdef", tableId: "ta_12345679abcdef",
version: "1", version: "1",

View File

@ -1,3 +1,6 @@
import fetch from "node-fetch"
// @ts-ignore
fetch.mockSearch()
import { import {
generateMakeRequest, generateMakeRequest,
MakeRequestResponse, MakeRequestResponse,
@ -16,6 +19,7 @@ import _ from "lodash"
import { generator } from "@budibase/backend-core/tests" import { generator } from "@budibase/backend-core/tests"
import { utils } from "@budibase/backend-core" import { utils } from "@budibase/backend-core"
import { GenericContainer } from "testcontainers" import { GenericContainer } from "testcontainers"
import { generateRowIdField } from "../integrations/utils"
const config = setup.getConfig()! const config = setup.getConfig()!
@ -80,16 +84,10 @@ describe("row api - postgres", () => {
name: "id", name: "id",
type: FieldType.AUTO, type: FieldType.AUTO,
autocolumn: true, autocolumn: true,
constraints: {
presence: true,
},
}, },
title: { title: {
name: "title", name: "title",
type: FieldType.STRING, type: FieldType.STRING,
constraints: {
presence: true,
},
}, },
}, },
sourceId: postgresDatasource._id, sourceId: postgresDatasource._id,
@ -121,16 +119,10 @@ describe("row api - postgres", () => {
name: "id", name: "id",
type: FieldType.AUTO, type: FieldType.AUTO,
autocolumn: true, autocolumn: true,
constraints: {
presence: true,
},
}, },
name: { name: {
name: "name", name: "name",
type: FieldType.STRING, type: FieldType.STRING,
constraints: {
presence: true,
},
}, },
description: { description: {
name: "description", name: "description",
@ -144,7 +136,6 @@ describe("row api - postgres", () => {
type: FieldType.LINK, type: FieldType.LINK,
constraints: { constraints: {
type: "array", type: "array",
presence: false,
}, },
fieldName: oneToManyRelationshipInfo.fieldName, fieldName: oneToManyRelationshipInfo.fieldName,
name: "oneToManyRelation", name: "oneToManyRelation",
@ -156,7 +147,6 @@ describe("row api - postgres", () => {
type: FieldType.LINK, type: FieldType.LINK,
constraints: { constraints: {
type: "array", type: "array",
presence: false,
}, },
fieldName: manyToOneRelationshipInfo.fieldName, fieldName: manyToOneRelationshipInfo.fieldName,
name: "manyToOneRelation", name: "manyToOneRelation",
@ -168,7 +158,6 @@ describe("row api - postgres", () => {
type: FieldType.LINK, type: FieldType.LINK,
constraints: { constraints: {
type: "array", type: "array",
presence: false,
}, },
fieldName: manyToManyRelationshipInfo.fieldName, fieldName: manyToManyRelationshipInfo.fieldName,
name: "manyToManyRelation", name: "manyToManyRelation",
@ -309,9 +298,6 @@ describe("row api - postgres", () => {
id: { id: {
name: "id", name: "id",
type: FieldType.AUTO, type: FieldType.AUTO,
constraints: {
presence: true,
},
}, },
}, },
sourceId: postgresDatasource._id, sourceId: postgresDatasource._id,
@ -921,47 +907,55 @@ describe("row api - postgres", () => {
foreignRows, foreignRows,
x => x.relationshipType x => x.relationshipType
) )
expect(res.body).toEqual({ const m2mFieldName = manyToManyRelationshipInfo.fieldName,
...rowData, o2mFieldName = oneToManyRelationshipInfo.fieldName,
[`fk_${oneToManyRelationshipInfo.table.name}_${oneToManyRelationshipInfo.fieldName}`]: m2oFieldName = manyToOneRelationshipInfo.fieldName
foreignRowsByType[RelationshipTypes.ONE_TO_MANY][0].row.id, const m2mRow1 = res.body[m2mFieldName].find(
[oneToManyRelationshipInfo.fieldName]: [ (row: Row) => row.id === 1
)
const m2mRow2 = res.body[m2mFieldName].find(
(row: Row) => row.id === 2
)
expect(m2mRow1).toEqual({
...foreignRowsByType[RelationshipTypes.MANY_TO_MANY][0].row,
[m2mFieldName]: [
{ {
...foreignRowsByType[RelationshipTypes.ONE_TO_MANY][0].row, _id: row._id,
_id: expect.any(String),
_rev: expect.any(String),
}, },
], ],
[manyToOneRelationshipInfo.fieldName]: [
{
...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][0].row,
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
row.id,
},
{
...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][1].row,
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
row.id,
},
{
...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][2].row,
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
row.id,
},
],
[manyToManyRelationshipInfo.fieldName]: [
{
...foreignRowsByType[RelationshipTypes.MANY_TO_MANY][0].row,
},
{
...foreignRowsByType[RelationshipTypes.MANY_TO_MANY][1].row,
},
],
id: row.id,
tableId: row.tableId,
_id: expect.any(String),
_rev: expect.any(String),
}) })
expect(m2mRow2).toEqual({
...foreignRowsByType[RelationshipTypes.MANY_TO_MANY][1].row,
[m2mFieldName]: [
{
_id: row._id,
},
],
})
expect(res.body[m2oFieldName]).toEqual([
{
...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][0].row,
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
row.id,
},
{
...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][1].row,
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
row.id,
},
{
...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][2].row,
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
row.id,
},
])
expect(res.body[o2mFieldName]).toEqual([
{
...foreignRowsByType[RelationshipTypes.ONE_TO_MANY][0].row,
_id: expect.any(String),
_rev: expect.any(String),
},
])
}) })
}) })
}) })

View File

@ -99,8 +99,8 @@ describe("Google Sheets Integration", () => {
}) })
}) })
test("removing an existing field will not remove the data from the spreadsheet", async () => { test("removing an existing field will remove the header from the google sheet", async () => {
await config.doInContext(structures.uuid(), async () => { const sheet = await config.doInContext(structures.uuid(), async () => {
const tableColumns = ["name"] const tableColumns = ["name"]
const table = createBasicTable(structures.uuid(), tableColumns) const table = createBasicTable(structures.uuid(), tableColumns)
@ -109,18 +109,14 @@ describe("Google Sheets Integration", () => {
}) })
sheetsByTitle[table.name] = sheet sheetsByTitle[table.name] = sheet
await integration.updateTable(table) await integration.updateTable(table)
return sheet
expect(sheet.loadHeaderRow).toBeCalledTimes(1)
expect(sheet.setHeaderRow).toBeCalledTimes(1)
expect(sheet.setHeaderRow).toBeCalledWith([
"name",
"description",
"location",
])
// No undefineds are sent
expect((sheet.setHeaderRow as any).mock.calls[0][0]).toHaveLength(3)
}) })
expect(sheet.loadHeaderRow).toBeCalledTimes(1)
expect(sheet.setHeaderRow).toBeCalledTimes(1)
expect(sheet.setHeaderRow).toBeCalledWith(["name"])
// No undefined are sent
expect((sheet.setHeaderRow as any).mock.calls[0][0]).toHaveLength(1)
}) })
}) })
}) })

View File

@ -9,3 +9,4 @@ process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error"
process.env.ENABLE_4XX_HTTP_LOGGING = "0" process.env.ENABLE_4XX_HTTP_LOGGING = "0"
process.env.MOCK_REDIS = "1" process.env.MOCK_REDIS = "1"
process.env.PLATFORM_URL = "http://localhost:10000" process.env.PLATFORM_URL = "http://localhost:10000"
process.env.REDIS_PASSWORD = "budibase"

View File

@ -46,6 +46,7 @@ import {
Row, Row,
SourceName, SourceName,
Table, Table,
SearchFilters,
} from "@budibase/types" } from "@budibase/types"
type DefaultUserValues = { type DefaultUserValues = {
@ -568,6 +569,16 @@ class TestConfiguration {
return this._req(null, { tableId }, controllers.row.fetch) return this._req(null, { tableId }, controllers.row.fetch)
} }
async searchRows(tableId: string, searchParams: SearchFilters = {}) {
if (!tableId && this.table) {
tableId = this.table._id
}
const body = {
query: searchParams,
}
return this._req(body, { tableId }, controllers.row.search)
}
// ROLE // ROLE
async createRole(config?: any) { async createRole(config?: any) {

View File

@ -24,10 +24,6 @@ export const init = () => {
} }
} }
} }
const clientLibPath = join(budibaseTempDir(), "budibase-client.js")
if (env.isTest() && !fs.existsSync(clientLibPath)) {
fs.copyFileSync(require.resolve("@budibase/client"), clientLibPath)
}
} }
/** /**

View File

@ -2,11 +2,6 @@
# yarn lockfile v1 # yarn lockfile v1
"@budibase/types@2.4.5-alpha.0":
version "2.4.5-alpha.0"
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.4.5-alpha.0.tgz#70fea09b5e471fe8fa6a760a1a2dd0dd74caac3a"
integrity sha512-tVFM9XnKwcCOo7nw6v7C8ZsK9hQLQBv3kHDn7/MFWnDMFCj72pUdtP/iFrAKr2c3tE84lkkWJfNHIolMSktHZA==
ansi-regex@^5.0.1: ansi-regex@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"

View File

@ -1,12 +1,13 @@
#!/bin/bash #!/bin/bash
set -e
if [[ -n $CI ]] if [[ -n $CI ]]
then then
# --runInBand performs better in ci where resources are limited # --runInBand performs better in ci where resources are limited
echo "jest --coverage --runInBand" echo "jest --coverage --runInBand --forceExit"
jest --coverage --runInBand jest --coverage --runInBand --forceExit
else else
# --maxWorkers performs better in development # --maxWorkers performs better in development
echo "jest --coverage --maxWorkers=2" echo "jest --coverage --maxWorkers=2 --forceExit"
jest --coverage --maxWorkers=2 jest --coverage --maxWorkers=2 --forceExit
fi fi

View File

@ -10,3 +10,4 @@ process.env.MINIO_SECRET_KEY = "test"
process.env.PLATFORM_URL = "http://localhost:10000" process.env.PLATFORM_URL = "http://localhost:10000"
process.env.INTERNAL_API_KEY = "tet" process.env.INTERNAL_API_KEY = "tet"
process.env.DISABLE_ACCOUNT_PORTAL = "0" process.env.DISABLE_ACCOUNT_PORTAL = "0"
process.env.REDIS_PASSWORD = "budibase"