From a8a7b6a100df1d051ade383571aa7d4a836491dc Mon Sep 17 00:00:00 2001 From: Sebastien Flory Date: Fri, 31 Jan 2025 18:18:04 +0100 Subject: [PATCH] Upg: tests now uses resources (#10427) * Upg: tests now uses resources * Fix: csv tests --- front/lib/api/data_sources.ts | 4 +- front/lib/resources/data_source_resource.ts | 5 +- .../resources/data_source_view_resource.ts | 42 +++++--- front/lib/resources/space_resource.ts | 17 ++- .../20240730_backfill_data_source_views.ts | 4 +- .../20240820_backfill_data_source_views.ts | 4 +- ...20240821_backfill_all_data_source_views.ts | 4 +- front/pages/api/templates/[tId]/index.test.ts | 11 +- front/pages/api/templates/index.test.ts | 8 +- front/pages/api/user/index.test.ts | 4 +- .../api/v1/w/[wId]/data_sources/index.test.ts | 20 ++-- .../api/v1/w/[wId]/feature_flags.test.ts | 14 +-- .../data_sources/[dsId]/tables/csv.test.ts | 100 ++++++++---------- .../[spaceId]/data_sources/index.test.ts | 64 ++++++----- .../pages/api/v1/w/[wId]/spaces/index.test.ts | 20 ++-- front/pages/api/w/[wId]/members/index.test.ts | 58 +++++----- .../pages/api/w/[wId]/members/search.test.ts | 30 +++--- .../[spaceId]/data_source_views/index.ts | 4 +- .../spaces/[spaceId]/data_sources/index.ts | 4 +- .../api/w/[wId]/spaces/[spaceId]/index.ts | 4 +- front/tests/utils/DataSourceFactory.ts | 35 ------ front/tests/utils/DataSourceViewFactory.ts | 60 ++++------- front/tests/utils/FeatureFlagFactory.ts | 17 +-- front/tests/utils/GroupFactory.ts | 38 ++----- front/tests/utils/GroupSpaceFactory.ts | 24 ++--- front/tests/utils/KeyFactory.ts | 69 ++++++------ front/tests/utils/MembershipFactory.ts | 44 ++------ front/tests/utils/SpaceFactory.ts | 64 +++++------ front/tests/utils/TemplateFactory.ts | 39 +++---- front/tests/utils/UserFactory.ts | 60 ++++------- front/tests/utils/WorkspaceFactory.ts | 17 +-- front/tests/utils/factories.ts | 22 ---- .../tests/utils/generic_private_api_tests.ts | 24 ++--- front/tests/utils/generic_public_api_tests.ts | 34 +++--- front/tests/utils/utils.ts | 41 +++---- 35 files changed, 405 insertions(+), 604 deletions(-) delete mode 100644 front/tests/utils/DataSourceFactory.ts delete mode 100644 front/tests/utils/factories.ts diff --git a/front/lib/api/data_sources.ts b/front/lib/api/data_sources.ts index aa79a90f69e8..171ef5095fa2 100644 --- a/front/lib/api/data_sources.ts +++ b/front/lib/api/data_sources.ts @@ -932,7 +932,6 @@ export async function createDataSourceWithoutProvider( const dataSourceView = await DataSourceViewResource.createDataSourceAndDefaultView( - auth, { name, description, @@ -942,7 +941,8 @@ export async function createDataSourceWithoutProvider( assistantDefaultSelected: false, conversationId: conversation?.id, }, - space + space, + auth.user() ); try { diff --git a/front/lib/resources/data_source_resource.ts b/front/lib/resources/data_source_resource.ts index b0e2667ef79b..0e29ae4f8951 100644 --- a/front/lib/resources/data_source_resource.ts +++ b/front/lib/resources/data_source_resource.ts @@ -4,6 +4,7 @@ import type { DataSourceType, ModelId, Result, + UserType, } from "@dust-tt/types"; import { formatUserFullName, Ok, removeNulls } from "@dust-tt/types"; import type { @@ -79,18 +80,18 @@ export class DataSourceResource extends ResourceWithSpace { } static async makeNew( - auth: Authenticator, blob: Omit< CreationAttributes, "editedAt" | "editedByUserId" | "vaultId" >, space: SpaceResource, + editedByUser?: UserType | null, transaction?: Transaction ) { const dataSource = await DataSourceModel.create( { ...blob, - editedByUserId: auth.user()?.id ?? null, + editedByUserId: editedByUser?.id ?? null, editedAt: new Date(), vaultId: space.id, }, diff --git a/front/lib/resources/data_source_view_resource.ts b/front/lib/resources/data_source_view_resource.ts index 7c074d663cb3..b46e703ad6cf 100644 --- a/front/lib/resources/data_source_view_resource.ts +++ b/front/lib/resources/data_source_view_resource.ts @@ -7,6 +7,7 @@ import type { DataSourceViewType, ModelId, Result, + UserType, } from "@dust-tt/types"; import { formatUserFullName, Ok, removeNulls } from "@dust-tt/types"; import assert from "assert"; @@ -88,19 +89,19 @@ export class DataSourceViewResource extends ResourceWithSpace, "editedAt" | "editedByUserId" | "vaultId" >, space: SpaceResource, dataSource: DataSourceResource, + editedByUser?: UserType | null, transaction?: Transaction ) { const dataSourceView = await DataSourceViewResource.model.create( { ...blob, - editedByUserId: auth.user()?.id ?? null, + editedByUserId: editedByUser?.id ?? null, editedAt: new Date(), vaultId: space.id, }, @@ -117,34 +118,40 @@ export class DataSourceViewResource extends ResourceWithSpace, "editedAt" | "vaultId">, - space: SpaceResource + space: SpaceResource, + editedByUser?: UserType | null, + transaction?: Transaction ) { - return frontSequelize.transaction(async (transaction) => { + const createDataSourceAndView = async (t: Transaction) => { const dataSource = await DataSourceResource.makeNew( - auth, blob, space, - transaction + editedByUser, + t ); return this.createDefaultViewInSpaceFromDataSourceIncludingAllDocuments( - auth, - dataSource.space, + space, dataSource, - transaction + editedByUser, + t ); - }); + }; + + if (transaction) { + return createDataSourceAndView(transaction); + } + + return frontSequelize.transaction(createDataSourceAndView); } static async createViewInSpaceFromDataSource( - auth: Authenticator, space: SpaceResource, dataSource: DataSourceResource, - parentsIn: string[] + parentsIn: string[], + editedByUser?: UserType | null ) { return this.makeNew( - auth, { dataSourceId: dataSource.id, parentsIn, @@ -152,19 +159,19 @@ export class DataSourceViewResource extends ResourceWithSpace { static async makeNew( blob: CreationAttributes, - groups: GroupResource[] + groups: GroupResource[], + transaction?: Transaction ) { - return frontSequelize.transaction(async (transaction) => { - const space = await SpaceModel.create(blob, { transaction }); + const createSpace = async (t: Transaction) => { + const space = await SpaceModel.create(blob, { transaction: t }); for (const group of groups) { await GroupSpaceModel.create( @@ -70,12 +71,18 @@ export class SpaceResource extends BaseResource { vaultId: space.id, workspaceId: space.workspaceId, }, - { transaction } + { transaction: t } ); } return new this(SpaceModel, space.get(), groups); - }); + }; + + if (transaction) { + return createSpace(transaction); + } + + return frontSequelize.transaction(createSpace); } static async makeDefaultsForWorkspace( diff --git a/front/migrations/20240730_backfill_data_source_views.ts b/front/migrations/20240730_backfill_data_source_views.ts index 0e0b25386902..aa6cfb5ce847 100644 --- a/front/migrations/20240730_backfill_data_source_views.ts +++ b/front/migrations/20240730_backfill_data_source_views.ts @@ -47,10 +47,10 @@ async function backfillDataSourceViewsForWorkspace( // Create a view for this data source in the global vault. await DataSourceViewResource.createViewInSpaceFromDataSource( - auth, globalVault, dataSource, - [] + [], + auth.user() ); updated++; diff --git a/front/migrations/20240820_backfill_data_source_views.ts b/front/migrations/20240820_backfill_data_source_views.ts index 662cf0a19a0a..0625cdfc57dd 100644 --- a/front/migrations/20240820_backfill_data_source_views.ts +++ b/front/migrations/20240820_backfill_data_source_views.ts @@ -39,10 +39,10 @@ async function backfillDefaultViewForDataSource( // Create a default view for this data source in the vault. await DataSourceViewResource.createViewInSpaceFromDataSource( - auth, vault, dataSource, - [] + [], + auth.user() ); logger.info(`View created for data source ${dataSource.id}.`); diff --git a/front/migrations/20240821_backfill_all_data_source_views.ts b/front/migrations/20240821_backfill_all_data_source_views.ts index a1091914a5d2..bae46779d359 100644 --- a/front/migrations/20240821_backfill_all_data_source_views.ts +++ b/front/migrations/20240821_backfill_all_data_source_views.ts @@ -35,10 +35,10 @@ async function backfillDefaultViewForDataSource( // Create a default view for this data source in the vault. await DataSourceViewResource.createViewInSpaceFromDataSource( - auth, space, dataSource, - [] + [], + auth.user() ); logger.info(`View created for data source ${dataSource.id}.`); diff --git a/front/pages/api/templates/[tId]/index.test.ts b/front/pages/api/templates/[tId]/index.test.ts index cc064b3009b2..231634dad805 100644 --- a/front/pages/api/templates/[tId]/index.test.ts +++ b/front/pages/api/templates/[tId]/index.test.ts @@ -2,8 +2,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { createMocks } from "node-mocks-http"; import { describe, expect, vi } from "vitest"; -import { TemplateResource } from "@app/lib/resources/template_resource"; -import { templateFactory } from "@app/tests/utils/TemplateFactory"; +import { TemplateFactory } from "@app/tests/utils/TemplateFactory"; import { itInTransaction } from "@app/tests/utils/utils"; import handler from "./index"; @@ -55,11 +54,11 @@ describe("GET /api/templates/[tId]", () => { }); itInTransaction("returns 404 when template is not published", async () => { - const template = await templateFactory().draft().create(); + const template = await TemplateFactory.draft(); const { req, res } = createMocks({ method: "GET", - query: { tId: TemplateResource.modelIdToSId(template) }, + query: { tId: template.sId }, headers: {}, }); @@ -77,11 +76,11 @@ describe("GET /api/templates/[tId]", () => { itInTransaction( "returns template when it exists and is published", async () => { - const template = await templateFactory().published().create(); + const template = await TemplateFactory.published(); const { req, res } = createMocks({ method: "GET", - query: { tId: TemplateResource.modelIdToSId(template) }, + query: { tId: template.sId }, headers: {}, }); diff --git a/front/pages/api/templates/index.test.ts b/front/pages/api/templates/index.test.ts index 5805453e4bfb..d7b111c86552 100644 --- a/front/pages/api/templates/index.test.ts +++ b/front/pages/api/templates/index.test.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { createMocks } from "node-mocks-http"; import { describe, expect, vi } from "vitest"; -import { templateFactory } from "@app/tests/utils/TemplateFactory"; +import { TemplateFactory } from "@app/tests/utils/TemplateFactory"; import { itInTransaction } from "@app/tests/utils/utils"; import handler from "./index"; @@ -40,9 +40,9 @@ describe("GET /api/templates", () => { }); // Create test templates - const publishedTemplate1 = await templateFactory().published().create(); - const publishedTemplate2 = await templateFactory().published().create(); - await templateFactory().draft().create(); // Draft template should not be returned + const publishedTemplate1 = await TemplateFactory.published(); + const publishedTemplate2 = await TemplateFactory.published(); + await TemplateFactory.draft(); // Draft template should not be returned await handler(req, res); diff --git a/front/pages/api/user/index.test.ts b/front/pages/api/user/index.test.ts index 435d4932d169..e746333e2ddd 100644 --- a/front/pages/api/user/index.test.ts +++ b/front/pages/api/user/index.test.ts @@ -1,6 +1,6 @@ import { describe, expect } from "vitest"; -import { UserModel } from "@app/lib/resources/storage/models/user"; +import { UserResource } from "@app/lib/resources/user_resource"; import { createPrivateApiMockRequest } from "@app/tests/utils/generic_private_api_tests"; import { itInTransaction } from "@app/tests/utils/utils"; @@ -60,7 +60,7 @@ describe("GET /api/user", () => { success: true, }); - const userAfterUpdate = await UserModel.findByPk(user.id); + const userAfterUpdate = await UserResource.fetchById(user.sId); expect(userAfterUpdate?.firstName).toBe("John"); expect(userAfterUpdate?.lastName).toBe("Doe"); }); diff --git a/front/pages/api/v1/w/[wId]/data_sources/index.test.ts b/front/pages/api/v1/w/[wId]/data_sources/index.test.ts index 96ae2dbda044..fc5431291ae4 100644 --- a/front/pages/api/v1/w/[wId]/data_sources/index.test.ts +++ b/front/pages/api/v1/w/[wId]/data_sources/index.test.ts @@ -1,9 +1,9 @@ import { describe, expect } from "vitest"; -import { dataSourceViewFactory } from "@app/tests/utils/DataSourceViewFactory"; +import { DataSourceViewFactory } from "@app/tests/utils/DataSourceViewFactory"; import { createPublicApiMockRequest } from "@app/tests/utils/generic_public_api_tests"; -import { groupSpaceFactory } from "@app/tests/utils/GroupSpaceFactory"; -import { spaceFactory } from "@app/tests/utils/SpaceFactory"; +import { GroupSpaceFactory } from "@app/tests/utils/GroupSpaceFactory"; +import { SpaceFactory } from "@app/tests/utils/SpaceFactory"; import { expectArrayOfObjectsWithSpecificLength, itInTransaction, @@ -20,22 +20,22 @@ describe("GET /api/v1/w/[wId]/data_sources (legacy endpoint)", () => { expect(res._getStatusCode()).toBe(500); }); - itInTransaction("returns data sources for the global space", async () => { + itInTransaction("returns data sources for the global space", async (t) => { const { req, res, workspace, globalGroup } = await createPublicApiMockRequest(); - const space = await spaceFactory().global(workspace).create(); - await groupSpaceFactory().associate(space, globalGroup); + const space = await SpaceFactory.global(workspace, t); + await GroupSpaceFactory.associate(space, globalGroup); // Create test data source views to the space - await dataSourceViewFactory().folder(workspace, space).create(); - await dataSourceViewFactory().folder(workspace, space).create(); + await DataSourceViewFactory.folder(workspace, space, t); + await DataSourceViewFactory.folder(workspace, space, t); // Create another space - const space2 = await spaceFactory().regular(workspace).create(); + const space2 = await SpaceFactory.regular(workspace, t); // Create test data source views to the space (they should not be returned) - await dataSourceViewFactory().folder(workspace, space2).create(); + await DataSourceViewFactory.folder(workspace, space2, t); // Execute request await handler(req, res); diff --git a/front/pages/api/v1/w/[wId]/feature_flags.test.ts b/front/pages/api/v1/w/[wId]/feature_flags.test.ts index a0f4aed715df..2be236c27dd6 100644 --- a/front/pages/api/v1/w/[wId]/feature_flags.test.ts +++ b/front/pages/api/v1/w/[wId]/feature_flags.test.ts @@ -1,14 +1,14 @@ import { describe, expect, vi } from "vitest"; import handler from "@app/pages/api/v1/w/[wId]/feature_flags"; -import { featureFlagFactory } from "@app/tests/utils/FeatureFlagFactory"; +import { FeatureFlagFactory } from "@app/tests/utils/FeatureFlagFactory"; import { createPublicApiAuthenticationTests, createPublicApiMockRequest, createPublicApiSystemOnlyAuthenticationTests, } from "@app/tests/utils/generic_public_api_tests"; import { itInTransaction } from "@app/tests/utils/utils"; -import { workspaceFactory } from "@app/tests/utils/WorkspaceFactory"; +import { WorkspaceFactory } from "@app/tests/utils/WorkspaceFactory"; // Mock the getSession function to return the user without going through the auth0 session // Not sure to understand why it's not working with the generic_public_api_tests.ts mock @@ -37,8 +37,8 @@ describe("GET /api/v1/w/[wId]/feature_flags", () => { }); // Add features flag - await featureFlagFactory().basic("deepseek_feature", workspace).create(); - await featureFlagFactory().basic("document_tracker", workspace).create(); + await FeatureFlagFactory.basic("deepseek_feature", workspace); + await FeatureFlagFactory.basic("document_tracker", workspace); await handler(req, res); @@ -97,10 +97,10 @@ describe("GET /api/v1/w/[wId]/feature_flags", () => { workspace: workspace1, } = await createPublicApiMockRequest({ systemKey: true }); - const workspace2 = await workspaceFactory().basic().create(); + const workspace2 = await WorkspaceFactory.basic(); - await featureFlagFactory().basic("labs_trackers", workspace1).create(); - await featureFlagFactory().basic("labs_transcripts", workspace2).create(); + await FeatureFlagFactory.basic("labs_trackers", workspace1); + await FeatureFlagFactory.basic("labs_transcripts", workspace2); await handler(req, res); diff --git a/front/pages/api/v1/w/[wId]/spaces/[spaceId]/data_sources/[dsId]/tables/csv.test.ts b/front/pages/api/v1/w/[wId]/spaces/[spaceId]/data_sources/[dsId]/tables/csv.test.ts index 292b6d64d016..d9d8131eaadc 100644 --- a/front/pages/api/v1/w/[wId]/spaces/[spaceId]/data_sources/[dsId]/tables/csv.test.ts +++ b/front/pages/api/v1/w/[wId]/spaces/[spaceId]/data_sources/[dsId]/tables/csv.test.ts @@ -1,19 +1,44 @@ import { describe, vi } from "vitest"; import { expect } from "vitest"; -import { DataSourceResource } from "@app/lib/resources/data_source_resource"; -import { SpaceResource } from "@app/lib/resources/space_resource"; -import { dataSourceFactory } from "@app/tests/utils/DataSourceFactory"; +import { DataSourceViewFactory } from "@app/tests/utils/DataSourceViewFactory"; import { createPublicApiMockRequest, createPublicApiSystemOnlyAuthenticationTests, } from "@app/tests/utils/generic_public_api_tests"; -import { groupSpaceFactory } from "@app/tests/utils/GroupSpaceFactory"; -import { spaceFactory } from "@app/tests/utils/SpaceFactory"; +import { GroupSpaceFactory } from "@app/tests/utils/GroupSpaceFactory"; +import { SpaceFactory } from "@app/tests/utils/SpaceFactory"; import { itInTransaction } from "@app/tests/utils/utils"; import handler from "./csv"; +const CORE_FAKE_RESPONSE = { + response: { + table: { + project: { project_id: 47 }, + data_source_id: + "21ab3a9994350d8bbd3f76e4c5d233696d6793b271f19407d60d7db825a16381", + data_source_internal_id: + "7f93516e45f485f18f889040ed13764a418acf422c34f4f0d3e9474ccccb5386", + created: 1738254966701, + table_id: "fooTable-1", + name: "footable", + description: "desc", + timestamp: 1738254966701, + tags: [], + title: "Wonderful table", + mime_type: "text/csv", + provider_visibility: null, + parent_id: null, + parents: ["fooTable-1"], + source_url: null, + schema: null, + schema_stale_at: null, + remote_database_table_id: null, + remote_database_secret_id: null, + }, + }, +}; describe( "system-only authentication tests", createPublicApiSystemOnlyAuthenticationTests(handler) @@ -29,27 +54,23 @@ vi.mock(import("@app/lib/api/config"), (() => ({ })) as any); describe("POST /api/v1/w/[wId]/spaces/[spaceId]/data_sources/[dsId]/tables/csv", () => { - itInTransaction("returns when called with a valid CSV", async () => { + itInTransaction("returns when called with a valid CSV", async (t) => { const { req, res, workspace, globalGroup } = await createPublicApiMockRequest({ systemKey: true, method: "POST", }); - const space = await spaceFactory().global(workspace).create(); - await groupSpaceFactory().associate(space, globalGroup); - const dataSource = await dataSourceFactory() - .folder(workspace, space) - .create(); + const space = await SpaceFactory.global(workspace, t); + await GroupSpaceFactory.associate(space, globalGroup); + const dataSourceView = await DataSourceViewFactory.folder( + workspace, + space, + t + ); - req.query.spaceId = SpaceResource.modelIdToSId({ - id: space.id, - workspaceId: workspace.id, - }); - req.query.dsId = DataSourceResource.modelIdToSId({ - id: dataSource.id, - workspaceId: workspace.id, - }); + req.query.spaceId = space.sId; + req.query.dsId = dataSourceView.dataSource.sId; req.body = { name: "footable", @@ -64,9 +85,6 @@ describe("POST /api/v1/w/[wId]/spaces/[spaceId]/data_sources/[dsId]/tables/csv", // First fetch is to create the table global.fetch = vi.fn().mockImplementation(async (url, init) => { const req = JSON.parse(init.body); - // console.log(">>>>>>>>>>>>>>>>>>>>>"); - // console.log("Request url", url); - // console.log("Request body:", JSON.stringify(req)); if ((url as string).endsWith("/tables")) { expect(req.table_id).toBe("fooTable-1"); @@ -74,39 +92,10 @@ describe("POST /api/v1/w/[wId]/spaces/[spaceId]/data_sources/[dsId]/tables/csv", expect(req.parents[0]).toBe("fooTable-1"); expect(req.source_url).toBeNull(); return Promise.resolve( - new Response( - JSON.stringify({ - response: { - table: { - project: { project_id: 47 }, - data_source_id: - "21ab3a9994350d8bbd3f76e4c5d233696d6793b271f19407d60d7db825a16381", - data_source_internal_id: - "7f93516e45f485f18f889040ed13764a418acf422c34f4f0d3e9474ccccb5386", - created: 1738254966701, - table_id: "fooTable-1", - name: "footable", - description: "desc", - timestamp: 1738254966701, - tags: [], - title: "Wonderful table", - mime_type: "text/csv", - provider_visibility: null, - parent_id: null, - parents: ["fooTable-1"], - source_url: null, - schema: null, - schema_stale_at: null, - remote_database_table_id: null, - remote_database_secret_id: null, - }, - }, - }), - { - status: 200, - headers: { "Content-Type": "application/json" }, - } - ) + new Response(JSON.stringify(CORE_FAKE_RESPONSE), { + status: 200, + headers: { "Content-Type": "application/json" }, + }) ); } @@ -133,5 +122,6 @@ describe("POST /api/v1/w/[wId]/spaces/[spaceId]/data_sources/[dsId]/tables/csv", await handler(req, res); expect(res._getStatusCode()).toBe(200); + expect(res._getJSONData()).toEqual(CORE_FAKE_RESPONSE.response); }); }); diff --git a/front/pages/api/v1/w/[wId]/spaces/[spaceId]/data_sources/index.test.ts b/front/pages/api/v1/w/[wId]/spaces/[spaceId]/data_sources/index.test.ts index 9f7d0b929dc6..bd25e3a41c53 100644 --- a/front/pages/api/v1/w/[wId]/spaces/[spaceId]/data_sources/index.test.ts +++ b/front/pages/api/v1/w/[wId]/spaces/[spaceId]/data_sources/index.test.ts @@ -1,13 +1,12 @@ import { describe, expect } from "vitest"; -import { SpaceResource } from "@app/lib/resources/space_resource"; -import { dataSourceViewFactory } from "@app/tests/utils/DataSourceViewFactory"; +import { DataSourceViewFactory } from "@app/tests/utils/DataSourceViewFactory"; import { createPublicApiAuthenticationTests, createPublicApiMockRequest, } from "@app/tests/utils/generic_public_api_tests"; -import { groupSpaceFactory } from "@app/tests/utils/GroupSpaceFactory"; -import { spaceFactory } from "@app/tests/utils/SpaceFactory"; +import { GroupSpaceFactory } from "@app/tests/utils/GroupSpaceFactory"; +import { SpaceFactory } from "@app/tests/utils/SpaceFactory"; import { expectArrayOfObjectsWithSpecificLength, itInTransaction, @@ -23,17 +22,14 @@ describe( describe("GET /api/v1/w/[wId]/spaces/[spaceId]/data_sources", () => { itInTransaction( "returns an empty list when no data sources exist", - async () => { + async (t) => { const { req, res, workspace, globalGroup } = await createPublicApiMockRequest(); - const space = await spaceFactory().global(workspace).create(); - await groupSpaceFactory().associate(space, globalGroup); + const space = await SpaceFactory.global(workspace, t); + await GroupSpaceFactory.associate(space, globalGroup); - req.query.spaceId = SpaceResource.modelIdToSId({ - id: space.id, - workspaceId: workspace.id, - }); + req.query.spaceId = space.sId; await handler(req, res); @@ -42,35 +38,35 @@ describe("GET /api/v1/w/[wId]/spaces/[spaceId]/data_sources", () => { } ); - itInTransaction("returns accessible data sources for the space", async () => { - const { req, res, workspace, globalGroup } = - await createPublicApiMockRequest(); + itInTransaction( + "returns accessible data sources for the space", + async (t) => { + const { req, res, workspace, globalGroup } = + await createPublicApiMockRequest(); - const space = await spaceFactory().global(workspace).create(); - await groupSpaceFactory().associate(space, globalGroup); + const space = await SpaceFactory.global(workspace, t); + await GroupSpaceFactory.associate(space, globalGroup); - req.query.spaceId = SpaceResource.modelIdToSId({ - id: space.id, - workspaceId: workspace.id, - }); + req.query.spaceId = space.sId; - // Create test data source views to the space - await dataSourceViewFactory().folder(workspace, space).create(); - await dataSourceViewFactory().folder(workspace, space).create(); + // Create test data source views to the space + await DataSourceViewFactory.folder(workspace, space, t); + await DataSourceViewFactory.folder(workspace, space, t); - // Create another space - const space2 = await spaceFactory().regular(workspace).create(); + // Create another space + const space2 = await SpaceFactory.regular(workspace, t); - // Create test data source views to the space (they should not be returned) - await dataSourceViewFactory().folder(workspace, space2).create(); + // Create test data source views to the space (they should not be returned) + await DataSourceViewFactory.folder(workspace, space2, t); - // Execute request - await handler(req, res); + // Execute request + await handler(req, res); - // Verify response - expect(res._getStatusCode()).toBe(200); + // Verify response + expect(res._getStatusCode()).toBe(200); - const { data_sources } = res._getJSONData(); - expectArrayOfObjectsWithSpecificLength(data_sources, 2); - }); + const { data_sources } = res._getJSONData(); + expectArrayOfObjectsWithSpecificLength(data_sources, 2); + } + ); }); diff --git a/front/pages/api/v1/w/[wId]/spaces/index.test.ts b/front/pages/api/v1/w/[wId]/spaces/index.test.ts index aadd99a7823f..8fa0da35b0d3 100644 --- a/front/pages/api/v1/w/[wId]/spaces/index.test.ts +++ b/front/pages/api/v1/w/[wId]/spaces/index.test.ts @@ -4,8 +4,8 @@ import { createPublicApiAuthenticationTests, createPublicApiMockRequest, } from "@app/tests/utils/generic_public_api_tests"; -import { groupSpaceFactory } from "@app/tests/utils/GroupSpaceFactory"; -import { spaceFactory } from "@app/tests/utils/SpaceFactory"; +import { GroupSpaceFactory } from "@app/tests/utils/GroupSpaceFactory"; +import { SpaceFactory } from "@app/tests/utils/SpaceFactory"; import { expectArrayOfObjectsWithSpecificLength, itInTransaction, @@ -28,21 +28,21 @@ describe("GET /api/v1/w/[wId]/spaces", () => { expect(res._getJSONData()).toEqual({ spaces: [] }); }); - itInTransaction("returns accessible spaces for the workspace", async () => { + itInTransaction("returns accessible spaces for the workspace", async (t) => { // Setup const { req, res, workspace, globalGroup } = await createPublicApiMockRequest(); // Create test spaces - const globalSpace = await spaceFactory().global(workspace).create(); - await spaceFactory().system(workspace).create(); // System spaces should not be returned unless your are admin (public api keys are builders) - const regularSpace1 = await spaceFactory().regular(workspace).create(); - const regularSpace2 = await spaceFactory().regular(workspace).create(); - await spaceFactory().regular(workspace).create(); // Unassociated space + const globalSpace = await SpaceFactory.global(workspace, t); + await SpaceFactory.system(workspace, t); // System spaces should not be returned unless your are admin (public api keys are builders) + const regularSpace1 = await SpaceFactory.regular(workspace, t); + const regularSpace2 = await SpaceFactory.regular(workspace, t); + await SpaceFactory.regular(workspace, t); // Unassociated space // Associate spaces with the global group - await groupSpaceFactory().associate(regularSpace1, globalGroup); - await groupSpaceFactory().associate(regularSpace2, globalGroup); + await GroupSpaceFactory.associate(regularSpace1, globalGroup); + await GroupSpaceFactory.associate(regularSpace2, globalGroup); // Execute request await handler(req, res); diff --git a/front/pages/api/w/[wId]/members/index.test.ts b/front/pages/api/w/[wId]/members/index.test.ts index f744fcae3b5b..2b4eb78127e5 100644 --- a/front/pages/api/w/[wId]/members/index.test.ts +++ b/front/pages/api/w/[wId]/members/index.test.ts @@ -1,11 +1,11 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { createMocks } from "node-mocks-http"; -import { describe, expect } from "vitest"; +import { describe, expect, vi } from "vitest"; import { parseQueryString } from "@app/lib/utils/router"; import { createPrivateApiMockRequest } from "@app/tests/utils/generic_private_api_tests"; -import { membershipFactory } from "@app/tests/utils/MembershipFactory"; -import { userFactory } from "@app/tests/utils/UserFactory"; +import { MembershipFactory } from "@app/tests/utils/MembershipFactory"; +import { UserFactory } from "@app/tests/utils/UserFactory"; import { itInTransaction } from "@app/tests/utils/utils"; import handler, { DEFAULT_PAGE_LIMIT, MAX_PAGE_LIMIT } from "./index"; @@ -19,15 +19,13 @@ describe("GET /api/w/[wId]/members", () => { // Create additional members const users = await Promise.all([ - userFactory().basic().create(), - userFactory().basic().create(), - userFactory().basic().create(), + UserFactory.basic(), + UserFactory.basic(), + UserFactory.basic(), ]); await Promise.all( - users.map((user) => - membershipFactory().associate(workspace, user, "user").create() - ) + users.map((user) => MembershipFactory.associate(workspace, user, "user")) ); await handler(req, res); @@ -69,15 +67,15 @@ describe("GET /api/w/[wId]/members", () => { // Create additional members with different roles const users = await Promise.all([ - userFactory().basic().create(), - userFactory().basic().create(), - userFactory().basic().create(), + UserFactory.basic(), + UserFactory.basic(), + UserFactory.basic(), ]); await Promise.all([ - membershipFactory().associate(workspace, users[0], "admin").create(), - membershipFactory().associate(workspace, users[1], "admin").create(), - membershipFactory().associate(workspace, users[2], "user").create(), + MembershipFactory.associate(workspace, users[0], "admin"), + MembershipFactory.associate(workspace, users[1], "admin"), + MembershipFactory.associate(workspace, users[2], "user"), ]); // Add admin role query parameter @@ -125,13 +123,11 @@ describe("GET /api/w/[wId]/members", () => { const users = await Promise.all( Array(DEFAULT_PAGE_LIMIT + 4) // +1 from createPrivateApiMockRequest .fill(null) - .map(() => userFactory().basic().create()) + .map(() => UserFactory.basic()) ); await Promise.all( - users.map((user) => - membershipFactory().associate(workspace, user, "user").create() - ) + users.map((user) => MembershipFactory.associate(workspace, user, "user")) ); await handler(req, res); @@ -155,12 +151,12 @@ describe("GET /api/w/[wId]/members", () => { const users = await Promise.all( Array(MAX_PAGE_LIMIT + 49) // +1 from createPrivateApiMockRequest .fill(null) - .map(() => userFactory().basic().create()) + .map(() => UserFactory.basic()) ); await Promise.all( users.map((user) => - membershipFactory().associate(workspace, user, "user").create() + MembershipFactory.associate(workspace, user, "user") ) ); @@ -188,10 +184,13 @@ describe("GET /api/w/[wId]/members", () => { for (let i = 0; i < 9; i++) { const createdAt = new Date(new Date().getTime() - (i + 1) * 1000); - const user = await userFactory().withCreatedAt(createdAt).create(); - await membershipFactory() - .associateWithCreatedAt(workspace, user, "user", createdAt) - .create(); + const user = await UserFactory.withCreatedAt(createdAt); + + vi.useFakeTimers(); + vi.setSystemTime(createdAt); + await MembershipFactory.associate(workspace, user, "user"); + vi.useRealTimers(); + users.push(user); } @@ -228,10 +227,11 @@ describe("GET /api/w/[wId]/members", () => { // Todo: we have to set the same date to both because pagination is done on membership createdAt // but we return users with their createdAt const createdAt = new Date(new Date().getTime() - (i + 1) * 1000); - const user = await userFactory().withCreatedAt(createdAt).create(); - await membershipFactory() - .associateWithCreatedAt(workspace, user, "user", createdAt) - .create(); + const user = await UserFactory.withCreatedAt(createdAt); + vi.useFakeTimers(); + vi.setSystemTime(createdAt); + await MembershipFactory.associate(workspace, user, "user"); + vi.useRealTimers(); users.push(user); } diff --git a/front/pages/api/w/[wId]/members/search.test.ts b/front/pages/api/w/[wId]/members/search.test.ts index e7d58b466638..e6e6efe7138c 100644 --- a/front/pages/api/w/[wId]/members/search.test.ts +++ b/front/pages/api/w/[wId]/members/search.test.ts @@ -2,8 +2,8 @@ import { describe, expect } from "vitest"; import { MAX_SEARCH_EMAILS } from "@app/lib/memberships"; import { createPrivateApiMockRequest } from "@app/tests/utils/generic_private_api_tests"; -import { membershipFactory } from "@app/tests/utils/MembershipFactory"; -import { userFactory } from "@app/tests/utils/UserFactory"; +import { MembershipFactory } from "@app/tests/utils/MembershipFactory"; +import { UserFactory } from "@app/tests/utils/UserFactory"; import { itInTransaction } from "@app/tests/utils/utils"; import handler from "./search"; @@ -54,15 +54,13 @@ describe("GET /api/w/[wId]/members/search", () => { // Create users with specific names for search const users = await Promise.all([ - userFactory().basic().create(), - userFactory().basic().create(), - userFactory().basic().create(), + UserFactory.basic(), + UserFactory.basic(), + UserFactory.basic(), ]); await Promise.all( - users.map((user) => - membershipFactory().associate(workspace, user, "user").create() - ) + users.map((user) => MembershipFactory.associate(workspace, user, "user")) ); req.query.searchTerm = users[0].email; @@ -83,15 +81,13 @@ describe("GET /api/w/[wId]/members/search", () => { }); const users = await Promise.all([ - userFactory().basic().create(), - userFactory().basic().create(), - userFactory().basic().create(), + UserFactory.basic(), + UserFactory.basic(), + UserFactory.basic(), ]); await Promise.all( - users.map((user) => - membershipFactory().associate(workspace, user, "user").create() - ) + users.map((user) => MembershipFactory.associate(workspace, user, "user")) ); req.query.searchEmails = users[0].email + "," + users[1].email; @@ -141,13 +137,11 @@ describe("GET /api/w/[wId]/members/search", () => { const users = await Promise.all( Array(29) .fill(null) - .map(() => userFactory().basic().create()) + .map(() => UserFactory.basic()) ); await Promise.all( - users.map((user) => - membershipFactory().associate(workspace, user, "user").create() - ) + users.map((user) => MembershipFactory.associate(workspace, user, "user")) ); req.query.limit = "20"; diff --git a/front/pages/api/w/[wId]/spaces/[spaceId]/data_source_views/index.ts b/front/pages/api/w/[wId]/spaces/[spaceId]/data_source_views/index.ts index b13b1765ecb8..415839867903 100644 --- a/front/pages/api/w/[wId]/spaces/[spaceId]/data_source_views/index.ts +++ b/front/pages/api/w/[wId]/spaces/[spaceId]/data_source_views/index.ts @@ -208,10 +208,10 @@ async function handler( } const dataSourceView = await DataSourceViewResource.createViewInSpaceFromDataSource( - auth, space, dataSource, - parentsIn + parentsIn, + auth.user() ); return res.status(201).json({ dataSourceView: dataSourceView.toJSON(), diff --git a/front/pages/api/w/[wId]/spaces/[spaceId]/data_sources/index.ts b/front/pages/api/w/[wId]/spaces/[spaceId]/data_sources/index.ts index 5b80e7ade13a..f7236192e1cb 100644 --- a/front/pages/api/w/[wId]/spaces/[spaceId]/data_sources/index.ts +++ b/front/pages/api/w/[wId]/spaces/[spaceId]/data_sources/index.ts @@ -384,7 +384,6 @@ const handleDataSourceWithProvider = async ({ const dataSourceView = await DataSourceViewResource.createDataSourceAndDefaultView( - auth, { assistantDefaultSelected: isConnectorProviderAssistantDefaultSelected(provider), @@ -395,7 +394,8 @@ const handleDataSourceWithProvider = async ({ name: dataSourceName, workspaceId: owner.id, }, - space + space, + auth.user() ); const { dataSource } = dataSourceView; diff --git a/front/pages/api/w/[wId]/spaces/[spaceId]/index.ts b/front/pages/api/w/[wId]/spaces/[spaceId]/index.ts index ab4a060dcb2f..173dbb543050 100644 --- a/front/pages/api/w/[wId]/spaces/[spaceId]/index.ts +++ b/front/pages/api/w/[wId]/spaces/[spaceId]/index.ts @@ -165,10 +165,10 @@ async function handler( ); if (dataSource) { await DataSourceViewResource.createViewInSpaceFromDataSource( - auth, space, dataSource, - dataSourceConfig.parentsIn + dataSourceConfig.parentsIn, + auth.user() ); } } diff --git a/front/tests/utils/DataSourceFactory.ts b/front/tests/utils/DataSourceFactory.ts deleted file mode 100644 index 8caf14253543..000000000000 --- a/front/tests/utils/DataSourceFactory.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { faker } from "@faker-js/faker"; -import type { InferCreationAttributes } from "sequelize"; - -import type { Workspace } from "@app/lib/models/workspace"; -import { DataSourceModel } from "@app/lib/resources/storage/models/data_source"; -import type { SpaceModel } from "@app/lib/resources/storage/models/spaces"; - -import { Factory } from "./factories"; - -class DataSourceFactory extends Factory { - constructor() { - super({ - name: "datasource " + faker.string.alphanumeric(8), - editedAt: new Date(), - assistantDefaultSelected: false, - dustAPIProjectId: "dust-project-id" + faker.string.alphanumeric(8), - dustAPIDataSourceId: "dust-datasource-id" + faker.string.alphanumeric(8), - }); - } - - async make(params: InferCreationAttributes) { - return DataSourceModel.create(params); - } - - folder(workspace: Workspace, space: SpaceModel) { - return this.params({ - workspaceId: workspace.id, - vaultId: space.id, - }); - } -} - -export const dataSourceFactory = () => { - return new DataSourceFactory(); -}; diff --git a/front/tests/utils/DataSourceViewFactory.ts b/front/tests/utils/DataSourceViewFactory.ts index ff48880a95fd..935eb1f1fe70 100644 --- a/front/tests/utils/DataSourceViewFactory.ts +++ b/front/tests/utils/DataSourceViewFactory.ts @@ -1,42 +1,28 @@ -import type { InferCreationAttributes } from "sequelize"; +import { faker } from "@faker-js/faker"; +import type { Transaction } from "sequelize"; import type { Workspace } from "@app/lib/models/workspace"; -import { DataSourceViewModel } from "@app/lib/resources/storage/models/data_source_view"; -import type { SpaceModel } from "@app/lib/resources/storage/models/spaces"; -import { dataSourceFactory } from "@app/tests/utils/DataSourceFactory"; +import { DataSourceViewResource } from "@app/lib/resources/data_source_view_resource"; +import type { SpaceResource } from "@app/lib/resources/space_resource"; -import { Factory } from "./factories"; - -class DataSourceViewFactory extends Factory { - constructor() { - super({ - editedAt: new Date(), - kind: "default", - parentsIn: null, - }); - } - - async make(params: InferCreationAttributes) { - if (!params.dataSourceId) { - // As a convenience, if the dataSourceId is not provided, we create a new data source - const dataSource = await dataSourceFactory().create({ - workspaceId: params.workspaceId, - vaultId: params.vaultId, - }); - params.dataSourceId = dataSource.id; - params.kind = "default"; - } - return DataSourceViewModel.create(params); - } - - folder(workspace: Workspace, space: SpaceModel) { - return this.params({ - workspaceId: workspace.id, - vaultId: space.id, - }); +export class DataSourceViewFactory { + static async folder( + workspace: Workspace, + space: SpaceResource, + t: Transaction + ) { + return DataSourceViewResource.createDataSourceAndDefaultView( + { + name: "datasource " + faker.string.alphanumeric(8), + assistantDefaultSelected: false, + dustAPIProjectId: "dust-project-id" + faker.string.alphanumeric(8), + dustAPIDataSourceId: + "dust-datasource-id" + faker.string.alphanumeric(8), + workspaceId: workspace.id, + }, + space, + null, + t + ); } } - -export const dataSourceViewFactory = () => { - return new DataSourceViewFactory(); -}; diff --git a/front/tests/utils/FeatureFlagFactory.ts b/front/tests/utils/FeatureFlagFactory.ts index 1db1ce440f45..f0705c736529 100644 --- a/front/tests/utils/FeatureFlagFactory.ts +++ b/front/tests/utils/FeatureFlagFactory.ts @@ -1,24 +1,13 @@ import type { WhitelistableFeature } from "@dust-tt/types"; -import type { InferCreationAttributes } from "sequelize"; import { FeatureFlag } from "@app/lib/models/feature_flag"; import type { Workspace } from "@app/lib/models/workspace"; -import { Factory } from "./factories"; - -class FeatureFlagFactory extends Factory { - async make(params: InferCreationAttributes) { - return FeatureFlag.create(params); - } - - basic(featureName: WhitelistableFeature, workspace: Workspace) { - return this.params({ +export class FeatureFlagFactory { + static async basic(featureName: WhitelistableFeature, workspace: Workspace) { + return FeatureFlag.create({ name: featureName, workspaceId: workspace.id, }); } } - -export const featureFlagFactory = () => { - return new FeatureFlagFactory(); -}; diff --git a/front/tests/utils/GroupFactory.ts b/front/tests/utils/GroupFactory.ts index 12c882cc7fa1..f8e3bf0333e6 100644 --- a/front/tests/utils/GroupFactory.ts +++ b/front/tests/utils/GroupFactory.ts @@ -1,33 +1,11 @@ -import { faker } from "@faker-js/faker"; -import type { InferCreationAttributes } from "sequelize"; - import type { Workspace } from "@app/lib/models/workspace"; -import { GroupModel } from "@app/lib/resources/storage/models/groups"; - -import { Factory } from "./factories"; - -class GroupFactory extends Factory { - async make(params: InferCreationAttributes) { - return GroupModel.create(params); - } - - global(workspace: Workspace) { - return this.params({ - name: "group " + faker.string.alphanumeric(8), - kind: "global", - workspaceId: workspace.id, - }); - } - - system(workspace: Workspace) { - return this.params({ - name: "group " + faker.string.alphanumeric(8), - kind: "system", - workspaceId: workspace.id, - }); +import { GroupResource } from "@app/lib/resources/group_resource"; +import { renderLightWorkspaceType } from "@app/lib/workspace"; + +export class GroupFactory { + static async defaults(workspace: Workspace) { + return GroupResource.makeDefaultsForWorkspace( + renderLightWorkspaceType({ workspace }) + ); } } - -export const groupFactory = () => { - return new GroupFactory(); -}; diff --git a/front/tests/utils/GroupSpaceFactory.ts b/front/tests/utils/GroupSpaceFactory.ts index 85b6e7b6eac9..a5ca3703c979 100644 --- a/front/tests/utils/GroupSpaceFactory.ts +++ b/front/tests/utils/GroupSpaceFactory.ts @@ -1,25 +1,13 @@ -import type { InferCreationAttributes } from "sequelize"; - +import type { GroupResource } from "@app/lib/resources/group_resource"; +import type { SpaceResource } from "@app/lib/resources/space_resource"; import { GroupSpaceModel } from "@app/lib/resources/storage/models/group_spaces"; -import type { GroupModel } from "@app/lib/resources/storage/models/groups"; -import type { SpaceModel } from "@app/lib/resources/storage/models/spaces"; - -import { Factory } from "./factories"; -class GroupSpaceFactory extends Factory { - async make(params: InferCreationAttributes) { - return GroupSpaceModel.create(params); - } - - associate(space: SpaceModel, group: GroupModel) { - return this.params({ +export class GroupSpaceFactory { + static async associate(space: SpaceResource, group: GroupResource) { + return GroupSpaceModel.create({ groupId: group.id, vaultId: space.id, workspaceId: space.workspaceId, - }).create(); + }); } } - -export const groupSpaceFactory = () => { - return new GroupSpaceFactory(); -}; diff --git a/front/tests/utils/KeyFactory.ts b/front/tests/utils/KeyFactory.ts index 59b47d779b77..09ebc84fe507 100644 --- a/front/tests/utils/KeyFactory.ts +++ b/front/tests/utils/KeyFactory.ts @@ -1,51 +1,48 @@ import { faker } from "@faker-js/faker"; import type { InferCreationAttributes } from "sequelize"; -import { SECRET_KEY_PREFIX } from "@app/lib/resources/key_resource"; -import type { GroupModel } from "@app/lib/resources/storage/models/groups"; +import type { GroupResource } from "@app/lib/resources/group_resource"; +import { KeyResource } from "@app/lib/resources/key_resource"; import { KeyModel } from "@app/lib/resources/storage/models/keys"; -import { Factory } from "./factories"; - -class KeyFactory extends Factory { +export class KeyFactory { async make(params: InferCreationAttributes) { return KeyModel.create(params); } - regular(group: GroupModel) { - return this.params({ - name: "key-" + faker.string.alphanumeric(8), - secret: SECRET_KEY_PREFIX + faker.string.alphanumeric(32), - groupId: group.id, - workspaceId: group.workspaceId, - isSystem: false, - status: "active", - }); + static async regular(group: GroupResource) { + return KeyResource.makeNew( + { + name: "key-" + faker.string.alphanumeric(8), + workspaceId: group.workspaceId, + isSystem: false, + status: "active", + }, + group + ); } - disabled(group: GroupModel) { - return this.params({ - name: "key-" + faker.string.alphanumeric(8), - secret: SECRET_KEY_PREFIX + faker.string.alphanumeric(32), - groupId: group.id, - workspaceId: group.workspaceId, - isSystem: false, - status: "disabled", - }); + static async disabled(group: GroupResource) { + return KeyResource.makeNew( + { + name: "key-" + faker.string.alphanumeric(8), + workspaceId: group.workspaceId, + isSystem: false, + status: "disabled", + }, + group + ); } - system(group: GroupModel) { - return this.params({ - name: "key-" + faker.string.alphanumeric(8), - secret: SECRET_KEY_PREFIX + faker.string.alphanumeric(32), - groupId: group.id, - workspaceId: group.workspaceId, - isSystem: true, - status: "active", - }); + static async system(group: GroupResource) { + return KeyResource.makeNew( + { + name: "key-" + faker.string.alphanumeric(8), + workspaceId: group.workspaceId, + isSystem: true, + status: "active", + }, + group + ); } } - -export const keyFactory = () => { - return new KeyFactory(); -}; diff --git a/front/tests/utils/MembershipFactory.ts b/front/tests/utils/MembershipFactory.ts index 766a2c5a3154..714bdf6214f3 100644 --- a/front/tests/utils/MembershipFactory.ts +++ b/front/tests/utils/MembershipFactory.ts @@ -1,44 +1,20 @@ import type { MembershipRoleType } from "@dust-tt/types"; -import type { InferCreationAttributes } from "sequelize"; import type { Workspace } from "@app/lib/models/workspace"; -import { MembershipModel } from "@app/lib/resources/storage/models/membership"; -import type { UserModel } from "@app/lib/resources/storage/models/user"; +import { MembershipResource } from "@app/lib/resources/membership_resource"; +import type { UserResource } from "@app/lib/resources/user_resource"; +import { renderLightWorkspaceType } from "@app/lib/workspace"; -import { Factory } from "./factories"; - -class MembershipFactory extends Factory { - async make(params: InferCreationAttributes) { - return MembershipModel.create(params); - } - - associate(workspace: Workspace, user: UserModel, role: MembershipRoleType) { - return this.params({ - role, - startAt: new Date(), - endAt: null, - userId: user.id, - workspaceId: workspace.id, - }); - } - - associateWithCreatedAt( +export class MembershipFactory { + static async associate( workspace: Workspace, - user: UserModel, - role: MembershipRoleType, - createdAt: Date + user: UserResource, + role: MembershipRoleType ) { - return this.params({ + return MembershipResource.createMembership({ + workspace: renderLightWorkspaceType({ workspace }), + user, role, - startAt: createdAt, - createdAt: createdAt, - endAt: null, - userId: user.id, - workspaceId: workspace.id, }); } } - -export const membershipFactory = () => { - return new MembershipFactory(); -}; diff --git a/front/tests/utils/SpaceFactory.ts b/front/tests/utils/SpaceFactory.ts index 9c53f1e2f9f9..76065958f68d 100644 --- a/front/tests/utils/SpaceFactory.ts +++ b/front/tests/utils/SpaceFactory.ts @@ -1,41 +1,43 @@ import { faker } from "@faker-js/faker"; -import type { InferCreationAttributes } from "sequelize"; +import type { Transaction } from "sequelize"; import type { Workspace } from "@app/lib/models/workspace"; -import { SpaceModel } from "@app/lib/resources/storage/models/spaces"; +import { SpaceResource } from "@app/lib/resources/space_resource"; -import { Factory } from "./factories"; - -class SpaceFactory extends Factory { - async make(params: InferCreationAttributes) { - return SpaceModel.create(params); - } - - global(workspace: Workspace) { - return this.params({ - name: "space " + faker.string.alphanumeric(8), - kind: "global", - workspaceId: workspace.id, - }); +export class SpaceFactory { + static async global(workspace: Workspace, t: Transaction) { + return SpaceResource.makeNew( + { + name: "space " + faker.string.alphanumeric(8), + kind: "global", + workspaceId: workspace.id, + }, + [], // TODO: Add groups + t + ); } - system(workspace: Workspace) { - return this.params({ - name: "space " + faker.string.alphanumeric(8), - kind: "system", - workspaceId: workspace.id, - }); + static async system(workspace: Workspace, t: Transaction) { + return SpaceResource.makeNew( + { + name: "space " + faker.string.alphanumeric(8), + kind: "system", + workspaceId: workspace.id, + }, + [], // TODO: Add groups + t + ); } - regular(workspace: Workspace) { - return this.params({ - name: "space " + faker.string.alphanumeric(8), - kind: "regular", - workspaceId: workspace.id, - }); + static async regular(workspace: Workspace, t: Transaction) { + return SpaceResource.makeNew( + { + name: "space " + faker.string.alphanumeric(8), + kind: "regular", + workspaceId: workspace.id, + }, + [], // TODO: Add groups + t + ); } } - -export const spaceFactory = () => { - return new SpaceFactory(); -}; diff --git a/front/tests/utils/TemplateFactory.ts b/front/tests/utils/TemplateFactory.ts index ed05f27a137c..e4e1ed0eceab 100644 --- a/front/tests/utils/TemplateFactory.ts +++ b/front/tests/utils/TemplateFactory.ts @@ -1,20 +1,17 @@ import { faker } from "@faker-js/faker"; -import type { InferCreationAttributes } from "sequelize"; -import { TemplateModel } from "@app/lib/resources/storage/models/templates"; +import { TemplateResource } from "@app/lib/resources/template_resource"; -import { Factory } from "./factories"; - -class TemplateFactory extends Factory { - constructor() { - super({ +export class TemplateFactory { + private static defaultParams = () => { + return { description: faker.company.catchPhrase(), backgroundColor: "#FFFFFF", emoji: faker.internet.emoji(), handle: faker.person.firstName(), - presetTemperature: "balanced", - presetProviderId: "anthropic", - presetModelId: "claude-3-opus-20240229", + presetTemperature: "balanced" as const, + presetProviderId: "anthropic" as const, + presetModelId: "claude-3-opus-20240229" as const, presetActions: [], tags: [], timeFrameDuration: null, @@ -23,26 +20,20 @@ class TemplateFactory extends Factory { presetInstructions: null, helpInstructions: null, helpActions: null, - }); - } + }; + }; - async make(params: InferCreationAttributes) { - return TemplateModel.create(params); - } - - published() { - return this.params({ + static async published() { + return TemplateResource.makeNew({ + ...this.defaultParams(), visibility: "published", }); } - draft() { - return this.params({ + static async draft() { + return TemplateResource.makeNew({ + ...this.defaultParams(), visibility: "draft", }); } } - -export const templateFactory = () => { - return new TemplateFactory(); -}; diff --git a/front/tests/utils/UserFactory.ts b/front/tests/utils/UserFactory.ts index 20b679c97f31..bf856f382a22 100644 --- a/front/tests/utils/UserFactory.ts +++ b/front/tests/utils/UserFactory.ts @@ -1,17 +1,17 @@ import { faker } from "@faker-js/faker"; -import type { InferCreationAttributes } from "sequelize"; -import { UserModel } from "@app/lib/resources/storage/models/user"; import { generateRandomModelSId } from "@app/lib/resources/string_ids"; - -import { Factory } from "./factories"; - -class UserFactory extends Factory { - constructor() { - super({ +import { UserResource } from "@app/lib/resources/user_resource"; + +export class UserFactory { + private static defaultParams = ( + superUser: boolean = false, + createdAt: Date = new Date() + ) => { + return { sId: generateRandomModelSId(), auth0Sub: faker.string.uuid(), - provider: "google", + provider: "google" as const, providerId: faker.string.uuid(), username: faker.internet.displayName(), @@ -20,41 +20,19 @@ class UserFactory extends Factory { firstName: faker.person.firstName(), lastName: faker.person.lastName(), - isDustSuperUser: false, - }); - } - - async make(params: InferCreationAttributes) { - return UserModel.create(params); - } + isDustSuperUser: superUser, + createdAt, + }; + }; - basic() { - return this.params({}); + static async basic() { + return UserResource.makeNew(this.defaultParams(false)); } - superUser() { - return this.params({ - isDustSuperUser: true, - }); + static async superUser() { + return UserResource.makeNew(this.defaultParams(true)); } - - withCreatedAt(createdAt: Date) { - return this.params({ - sId: generateRandomModelSId(), - auth0Sub: faker.string.uuid(), - provider: "google", - providerId: faker.string.uuid(), - - username: faker.internet.displayName(), - email: faker.internet.email(), - name: faker.person.fullName(), - firstName: faker.person.firstName(), - lastName: faker.person.lastName(), - createdAt, - }); + static async withCreatedAt(createdAt: Date) { + return UserResource.makeNew(this.defaultParams(false, createdAt)); } } - -export const userFactory = () => { - return new UserFactory(); -}; diff --git a/front/tests/utils/WorkspaceFactory.ts b/front/tests/utils/WorkspaceFactory.ts index 588b82ce73e8..c12bcba78c66 100644 --- a/front/tests/utils/WorkspaceFactory.ts +++ b/front/tests/utils/WorkspaceFactory.ts @@ -1,25 +1,14 @@ import { faker } from "@faker-js/faker"; -import type { InferCreationAttributes } from "sequelize"; import { Workspace } from "@app/lib/models/workspace"; import { generateRandomModelSId } from "@app/lib/resources/string_ids"; -import { Factory } from "./factories"; - -class WorkspaceFactory extends Factory { - async make(params: InferCreationAttributes) { - return Workspace.create(params); - } - - basic() { - return this.params({ +export class WorkspaceFactory { + static async basic() { + return Workspace.create({ sId: generateRandomModelSId(), name: faker.company.name(), description: faker.company.catchPhrase(), }); } } - -export const workspaceFactory = () => { - return new WorkspaceFactory(); -}; diff --git a/front/tests/utils/factories.ts b/front/tests/utils/factories.ts deleted file mode 100644 index 52cafd71997d..000000000000 --- a/front/tests/utils/factories.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { InferCreationAttributes, Model } from "sequelize"; - -export abstract class Factory { - attrs: Partial> = {}; - - constructor(attrs?: Partial>) { - if (attrs) { - this.attrs = attrs; - } - } - - abstract make(params: Partial>): Promise; - - params(newAttrs: Partial>) { - this.attrs = { ...this.attrs, ...newAttrs }; - return this; - } - - async create(params?: Partial>): Promise { - return this.make({ ...this.attrs, ...params }); - } -} diff --git a/front/tests/utils/generic_private_api_tests.ts b/front/tests/utils/generic_private_api_tests.ts index 5d156bbcd81b..237f401065a4 100644 --- a/front/tests/utils/generic_private_api_tests.ts +++ b/front/tests/utils/generic_private_api_tests.ts @@ -4,10 +4,10 @@ import type { RequestMethod } from "node-mocks-http"; import { createMocks } from "node-mocks-http"; import { vi } from "vitest"; -import { groupFactory } from "@app/tests/utils/GroupFactory"; -import { membershipFactory } from "@app/tests/utils/MembershipFactory"; -import { userFactory } from "@app/tests/utils/UserFactory"; -import { workspaceFactory } from "@app/tests/utils/WorkspaceFactory"; +import { GroupFactory } from "@app/tests/utils/GroupFactory"; +import { MembershipFactory } from "@app/tests/utils/MembershipFactory"; +import { UserFactory } from "@app/tests/utils/UserFactory"; +import { WorkspaceFactory } from "@app/tests/utils/WorkspaceFactory"; vi.mock(import("../../lib/auth"), async (importOriginal) => { const mod = await importOriginal(); @@ -46,15 +46,13 @@ export const createPrivateApiMockRequest = async ({ role?: MembershipRoleType; isSuperUser?: boolean; } = {}) => { - const workspace = await workspaceFactory().basic().create(); - const user = await ( - isSuperUser ? userFactory().superUser() : userFactory().basic() - ).create(); - const globalGroup = await groupFactory().global(workspace).create(); + const workspace = await WorkspaceFactory.basic(); + const user = await (isSuperUser + ? UserFactory.superUser() + : UserFactory.basic()); + const { globalGroup, systemGroup } = await GroupFactory.defaults(workspace); - const membership = await membershipFactory() - .associate(workspace, user, role) - .create(); + const membership = await MembershipFactory.associate(workspace, user, role); // Mock the getSession function to return the user without going through the auth0 session vi.mocked(getSession).mockReturnValue( @@ -75,5 +73,5 @@ export const createPrivateApiMockRequest = async ({ headers: {}, }); - return { req, res, workspace, user, membership, globalGroup }; + return { req, res, workspace, user, membership, globalGroup, systemGroup }; }; diff --git a/front/tests/utils/generic_public_api_tests.ts b/front/tests/utils/generic_public_api_tests.ts index d17df02b17ea..3da8aea3359a 100644 --- a/front/tests/utils/generic_public_api_tests.ts +++ b/front/tests/utils/generic_public_api_tests.ts @@ -4,10 +4,10 @@ import { createMocks } from "node-mocks-http"; import { expect, vi } from "vitest"; import { SECRET_KEY_PREFIX } from "@app/lib/resources/key_resource"; -import { groupFactory } from "@app/tests/utils/GroupFactory"; -import { keyFactory } from "@app/tests/utils/KeyFactory"; +import { GroupFactory } from "@app/tests/utils/GroupFactory"; +import { KeyFactory } from "@app/tests/utils/KeyFactory"; import { itInTransaction } from "@app/tests/utils/utils"; -import { workspaceFactory } from "@app/tests/utils/WorkspaceFactory"; +import { WorkspaceFactory } from "@app/tests/utils/WorkspaceFactory"; // Mock the getSession function to return the user without going through the auth0 session vi.mock(import("../../lib/auth"), async (importOriginal) => { @@ -44,11 +44,11 @@ export const createPublicApiMockRequest = async ({ systemKey = false, method = "GET", }: { systemKey?: boolean; method?: RequestMethod } = {}) => { - const workspace = await workspaceFactory().basic().create(); - const globalGroup = await groupFactory().global(workspace).create(); + const workspace = await WorkspaceFactory.basic(); + const { globalGroup, systemGroup } = await GroupFactory.defaults(workspace); const key = systemKey - ? await keyFactory().system(globalGroup).create() - : await keyFactory().regular(globalGroup).create(); + ? await KeyFactory.system(globalGroup) + : await KeyFactory.regular(globalGroup); const { req, res } = createMocks({ method: method, @@ -58,7 +58,7 @@ export const createPublicApiMockRequest = async ({ }, }); - return { req, res, workspace, globalGroup, key }; + return { req, res, workspace, globalGroup, systemGroup, key }; }; export function createPublicApiSystemOnlyAuthenticationTests( @@ -84,7 +84,7 @@ export function createPublicApiSystemOnlyAuthenticationTests( export function createPublicApiAuthenticationTests(handler: NextHandler) { return () => { itInTransaction("GET returns 401 if no key", async () => { - const workspace = await workspaceFactory().basic().create(); + const workspace = await WorkspaceFactory.basic(); const { req, res } = createMocks({ method: "GET", @@ -104,9 +104,9 @@ export function createPublicApiAuthenticationTests(handler: NextHandler) { }); itInTransaction("returns 401 if disabled key", async () => { - const workspace = await workspaceFactory().basic().create(); - const globalGroup = await groupFactory().global(workspace).create(); - const key = await keyFactory().disabled(globalGroup).create(); + const workspace = await WorkspaceFactory.basic(); + const { globalGroup } = await GroupFactory.defaults(workspace); + const key = await KeyFactory.disabled(globalGroup); const { req, res } = createMocks({ method: "GET", @@ -128,7 +128,7 @@ export function createPublicApiAuthenticationTests(handler: NextHandler) { }); itInTransaction("returns 401 if invalid key", async () => { - const workspace = await workspaceFactory().basic().create(); + const workspace = await WorkspaceFactory.basic(); const { req, res } = createMocks({ method: "GET", @@ -194,11 +194,11 @@ export function createPublicApiAuthenticationTests(handler: NextHandler) { itInTransaction( "returns 401 when workspace does not match the key", async () => { - const workspace = await workspaceFactory().basic().create(); - const globalGroup = await groupFactory().global(workspace).create(); - const key = await keyFactory().regular(globalGroup).create(); + const workspace = await WorkspaceFactory.basic(); + const { globalGroup } = await GroupFactory.defaults(workspace); + const key = await KeyFactory.regular(globalGroup); - const workspace2 = await workspaceFactory().basic().create(); + const workspace2 = await WorkspaceFactory.basic(); const { req, res } = createMocks({ method: "GET", diff --git a/front/tests/utils/utils.ts b/front/tests/utils/utils.ts index 4aef3b824b60..933e8ab29e3d 100644 --- a/front/tests/utils/utils.ts +++ b/front/tests/utils/utils.ts @@ -1,35 +1,26 @@ +import type { Transaction } from "sequelize"; import { expect, it } from "vitest"; import { frontSequelize } from "@app/lib/resources/storage"; export const itInTransaction = function ( title: string, - fn: () => Promise + fn: (t: Transaction) => Promise ) { - return it(title, function () { - return new Promise((resolve, reject) => { - frontSequelize - .transaction(() => { - return fn() - .then(() => { - resolve(); - }) - .catch((err: any) => { - reject(err); - }) - .finally(() => { - throw "Rollback"; - }); - }) - .catch((err: any) => { - if (err === "Rollback") { - return; - } - reject(err); - console.log("Error in test:"); - console.log(err); - }); - }); + return it(title, async function () { + try { + await frontSequelize.transaction(async (t) => { + await fn(t); + throw "Rollback"; // Force rollback after successful execution + }); + } catch (err) { + if (err === "Rollback") { + return; + } + console.log("Error in test:"); + console.log(err); + throw err; + } }); };