Minor refactor to accomodate testing with snippets. More test cases for multiple binding types
This commit is contained in:
parent
2997da8687
commit
5e7d1169f7
|
@ -292,7 +292,7 @@ export async function ensureSnippetContext() {
|
|||
// Otherwise get snippets for this app and update context
|
||||
let snippets: Snippet[] | undefined
|
||||
const db = getAppDB()
|
||||
if (db && !env.isTest()) {
|
||||
if (db) {
|
||||
const app = await db.get<App>(DocumentType.APP_METADATA)
|
||||
snippets = app.snippets
|
||||
}
|
||||
|
|
|
@ -325,7 +325,6 @@
|
|||
<style>
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 1000px;
|
||||
}
|
||||
.fields {
|
||||
display: grid;
|
||||
|
|
|
@ -198,15 +198,12 @@ export async function destroy(ctx: UserCtx<DeleteRowRequest>) {
|
|||
export async function search(ctx: Ctx<SearchRowRequest, SearchRowResponse>) {
|
||||
const tableId = utils.getTableId(ctx)
|
||||
|
||||
// Current user context for bindable search
|
||||
const { _id, _rev, firstName, lastName, email, status, roleId } = ctx.user
|
||||
|
||||
await context.ensureSnippetContext()
|
||||
|
||||
const enrichedQuery = await utils.enrichSearchContext(
|
||||
{ ...ctx.request.body.query },
|
||||
{
|
||||
user: { _id, _rev, firstName, lastName, email, status, roleId },
|
||||
user: sdk.users.getUserContextBindings(ctx.user),
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -57,13 +57,10 @@ export async function searchView(
|
|||
})
|
||||
}
|
||||
|
||||
// Current user search context.
|
||||
const { _id, _rev, firstName, lastName, email, status, roleId } = ctx.user
|
||||
|
||||
await context.ensureSnippetContext()
|
||||
|
||||
const enrichedQuery = await enrichSearchContext(query, {
|
||||
user: { _id, _rev, firstName, lastName, email, status, roleId },
|
||||
user: sdk.users.getUserContextBindings(ctx.user),
|
||||
})
|
||||
|
||||
const searchOptions: RequiredKeys<SearchViewRowRequest> &
|
||||
|
|
|
@ -174,29 +174,28 @@ describe.each([
|
|||
// Ensure all bindings resolve and perform as expected
|
||||
describe("bindings", () => {
|
||||
let globalUsers: any = []
|
||||
let globalUserIds: any = []
|
||||
|
||||
const future = new Date(serverTime.getTime())
|
||||
future.setDate(future.getDate() + 30)
|
||||
|
||||
const rows = (currentUser: User) => {
|
||||
globalUserIds = globalUsers.map((user: any) => {
|
||||
return user._id
|
||||
})
|
||||
return [
|
||||
{ name: "foo", appointment: "1982-01-05T00:00:00.000Z" },
|
||||
{ name: "bar", appointment: "1995-05-06T00:00:00.000Z" },
|
||||
{ name: currentUser.firstName, appointment: future.toISOString() },
|
||||
{ name: "pivot", appointment: serverTime.toISOString() },
|
||||
{ name: "single user, session user", single_user: currentUser._id },
|
||||
{ name: "single user", single_user: globalUserIds[0] },
|
||||
{ name: "serverDate", appointment: serverTime.toISOString() },
|
||||
{
|
||||
name: "single user, session user",
|
||||
single_user: JSON.stringify([currentUser]),
|
||||
},
|
||||
{ name: "single user", single_user: JSON.stringify([globalUsers[0]]) },
|
||||
{
|
||||
name: "multi user",
|
||||
multi_user: globalUserIds,
|
||||
multi_user: JSON.stringify(globalUsers),
|
||||
},
|
||||
{
|
||||
name: "multi user with session user",
|
||||
multi_user: [...globalUserIds, currentUser._id],
|
||||
multi_user: JSON.stringify([...globalUsers, currentUser]),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -257,7 +256,7 @@ describe.each([
|
|||
name: config.getUser().firstName,
|
||||
appointment: future.toISOString(),
|
||||
},
|
||||
{ name: "pivot", appointment: serverTime.toISOString() },
|
||||
{ name: "serverDate", appointment: serverTime.toISOString() },
|
||||
])
|
||||
})
|
||||
|
||||
|
@ -272,11 +271,11 @@ describe.each([
|
|||
}).toContainExactly([
|
||||
{ name: "foo", appointment: "1982-01-05T00:00:00.000Z" },
|
||||
{ name: "bar", appointment: "1995-05-06T00:00:00.000Z" },
|
||||
{ name: "pivot", appointment: serverTime.toISOString() },
|
||||
{ name: "serverDate", appointment: serverTime.toISOString() },
|
||||
])
|
||||
})
|
||||
|
||||
it("should parse the encoded js snippet. One week prior", async () => {
|
||||
it("should parse the encoded js snippet. Return rows with appointments up to 1 week in the past", async () => {
|
||||
const jsBinding = "return snippets.WeeksAgo();"
|
||||
const encodedBinding = encodeJSBinding(jsBinding)
|
||||
|
||||
|
@ -293,7 +292,7 @@ describe.each([
|
|||
])
|
||||
})
|
||||
|
||||
it("should parse the encoded js binding. 2 weeks prior", async () => {
|
||||
it("should parse the encoded js binding. Return rows with appointments 2 weeks in the past", async () => {
|
||||
const jsBinding =
|
||||
"const currentTime = new Date()\ncurrentTime.setDate(currentTime.getDate()-14);\nreturn currentTime.toISOString();"
|
||||
const encodedBinding = encodeJSBinding(jsBinding)
|
||||
|
@ -333,7 +332,7 @@ describe.each([
|
|||
])
|
||||
})
|
||||
|
||||
it("should match the session user id in a multi user field", async () => {
|
||||
it("should not match the session user id in a multi user field", async () => {
|
||||
await expectQuery({
|
||||
notContains: { multi_user: ["{{ [user]._id }}"] },
|
||||
notEmpty: { multi_user: true },
|
||||
|
@ -341,13 +340,47 @@ describe.each([
|
|||
{
|
||||
name: "multi user",
|
||||
multi_user: globalUsers.map((user: any) => {
|
||||
return {
|
||||
_id: user._id,
|
||||
}
|
||||
return { _id: user._id }
|
||||
}),
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("should match the session user id and a user table row id using helpers, user binding and a static user id.", async () => {
|
||||
await expectQuery({
|
||||
oneOf: {
|
||||
single_user: [
|
||||
"{{ default [user]._id '_empty_' }}",
|
||||
globalUsers[0]._id,
|
||||
],
|
||||
},
|
||||
}).toContainExactly([
|
||||
{
|
||||
name: "single user, session user",
|
||||
single_user: [{ _id: config.getUser()._id }],
|
||||
},
|
||||
{
|
||||
name: "single user",
|
||||
single_user: [{ _id: globalUsers[0]._id }],
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it("should resolve 'default' helper to '_empty_' when binding resolves to nothing", async () => {
|
||||
await expectQuery({
|
||||
oneOf: {
|
||||
single_user: [
|
||||
"{{ default [user]._idx '_empty_' }}",
|
||||
globalUsers[0]._id,
|
||||
],
|
||||
},
|
||||
}).toContainExactly([
|
||||
{
|
||||
name: "single user",
|
||||
single_user: [{ _id: globalUsers[0]._id }],
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("strings", () => {
|
||||
|
|
|
@ -36,7 +36,7 @@ function waitForUpdate(opts: { group?: boolean }) {
|
|||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
await config.init("syncApp")
|
||||
await config.init({ appName: "syncApp" })
|
||||
})
|
||||
|
||||
async function createUser(email: string, roles: UserRoles, builder?: boolean) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
UserMetadata,
|
||||
Database,
|
||||
ContextUserMetadata,
|
||||
UserCtx,
|
||||
} from "@budibase/types"
|
||||
|
||||
export function combineMetadataAndUser(
|
||||
|
@ -124,3 +125,12 @@ export async function syncGlobalUsers() {
|
|||
await db.bulkDocs(toWrite)
|
||||
}
|
||||
}
|
||||
|
||||
export function getUserContextBindings(user: ContextUser) {
|
||||
if (!user) {
|
||||
return {}
|
||||
}
|
||||
// Current user context for bindable search
|
||||
const { _id, _rev, firstName, lastName, email, status, roleId } = user
|
||||
return { _id, _rev, firstName, lastName, email, status, roleId }
|
||||
}
|
||||
|
|
|
@ -81,6 +81,12 @@ mocks.licenses.useUnlimited()
|
|||
|
||||
dbInit()
|
||||
|
||||
export interface CreateAppRequest {
|
||||
appName: string
|
||||
url?: string
|
||||
snippets?: any[]
|
||||
}
|
||||
|
||||
export interface TableToBuild extends Omit<Table, "sourceId" | "sourceType"> {
|
||||
sourceId?: string
|
||||
sourceType?: TableSourceType
|
||||
|
@ -218,11 +224,14 @@ export default class TestConfiguration {
|
|||
// SETUP / TEARDOWN
|
||||
|
||||
// use a new id as the name to avoid name collisions
|
||||
async init(appName = newid()) {
|
||||
async init(opts = {}) {
|
||||
if (!this.started) {
|
||||
await startup()
|
||||
}
|
||||
return this.newTenant(appName)
|
||||
return this.newTenant({
|
||||
appName: newid(),
|
||||
...opts,
|
||||
})
|
||||
}
|
||||
|
||||
end() {
|
||||
|
@ -542,14 +551,14 @@ export default class TestConfiguration {
|
|||
return this.tenantId
|
||||
}
|
||||
|
||||
async newTenant(appName = newid()): Promise<App> {
|
||||
async newTenant(opts: {}): Promise<App> {
|
||||
this.csrfToken = generator.hash()
|
||||
|
||||
this.tenantId = structures.tenant.id()
|
||||
this.user = await this.globalUser()
|
||||
this.userMetadataId = generateUserMetadataID(this.user._id!)
|
||||
|
||||
return this.createApp(appName)
|
||||
return this.createApp({ appName: newid(), ...opts })
|
||||
}
|
||||
|
||||
doInTenant<T>(task: () => T) {
|
||||
|
@ -579,9 +588,9 @@ export default class TestConfiguration {
|
|||
}
|
||||
|
||||
// APP
|
||||
async createApp(appName: string, url?: string): Promise<App> {
|
||||
// create dev app
|
||||
// clear any old app
|
||||
async createApp(opts: CreateAppRequest): Promise<App> {
|
||||
const { appName, url, snippets } = opts
|
||||
|
||||
this.appId = undefined
|
||||
this.app = await context.doInTenant(
|
||||
this.tenantId!,
|
||||
|
@ -592,6 +601,20 @@ export default class TestConfiguration {
|
|||
})) as App
|
||||
)
|
||||
this.appId = this.app.appId
|
||||
|
||||
if (snippets) {
|
||||
this.app = await this._req(
|
||||
appController.update,
|
||||
{
|
||||
...this.app,
|
||||
snippets,
|
||||
},
|
||||
{
|
||||
appId: this.appId,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return await context.doInAppContext(this.app.appId!, async () => {
|
||||
// create production app
|
||||
this.prodApp = await this.publish()
|
||||
|
|
Loading…
Reference in New Issue