@prismicio/e2e-tests-utils 1.12.0-alpha.1 → 1.12.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,166 @@
1
+ import axios, { AxiosInstance } from "axios";
2
+
3
+ import { IntegrationFieldConfig, IntegrationFieldData } from "../types";
4
+
5
+ import { logHttpResponse } from "../utils/log";
6
+ import { toSnakeCase } from "../utils/strings";
7
+
8
+ import { CustomTypesApiClient } from "./customTypesApi";
9
+ import { WroomClient } from "./wroom";
10
+
11
+ /**
12
+ * Client for interacting with Integration Fields routes to create integration
13
+ * field catalogs and add them to custom type fields.
14
+ */
15
+ export class IntegrationFieldsClient {
16
+ private readonly baseURL: string;
17
+ private readonly customTypesApiClient: CustomTypesApiClient;
18
+ private readonly wroomClient: WroomClient;
19
+ private readonly repository: string;
20
+ private readonly tokens: Record<string, string> = {};
21
+
22
+ constructor(
23
+ baseURL: string,
24
+ config: {
25
+ customTypesApiClient: CustomTypesApiClient;
26
+ wroomClient: WroomClient;
27
+ repository: string;
28
+ },
29
+ ) {
30
+ this.baseURL = baseURL;
31
+ this.customTypesApiClient = config.customTypesApiClient;
32
+ this.wroomClient = config.wroomClient;
33
+ this.repository = config.repository;
34
+ }
35
+
36
+ private async getClient(catalogId: string): Promise<AxiosInstance> {
37
+ const token = this.tokens[catalogId] || (await this.createToken(catalogId));
38
+
39
+ const client = axios.create({
40
+ baseURL: `${this.baseURL}/if/`,
41
+ withCredentials: true,
42
+ validateStatus: () => true,
43
+ headers: {
44
+ "User-Agent": "prismic-cli/prismic-e2e-tests-utils",
45
+ Authorization: `Bearer ${token}`,
46
+ },
47
+ });
48
+
49
+ return client;
50
+ }
51
+
52
+ private async addCatalog({
53
+ name,
54
+ description,
55
+ }: {
56
+ name: string;
57
+ description: string;
58
+ }): Promise<string> {
59
+ const response = await this.wroomClient.post(
60
+ this.repository,
61
+ "app/settings/integrationfields/pushcustom",
62
+ {
63
+ "catalog-name": name,
64
+ "catalog-description": description,
65
+ },
66
+ );
67
+
68
+ const { data, status } = response;
69
+ const success =
70
+ status === 200 ||
71
+ (status === 400 &&
72
+ (data as string).includes("Already existing integration field"));
73
+ if (!success) {
74
+ logHttpResponse(response);
75
+ throw new Error(`Could not add integration field catalog ${name}`);
76
+ }
77
+
78
+ return `${this.repository}--${toSnakeCase(name)}`;
79
+ }
80
+
81
+ private async createToken(catalogId: string): Promise<void> {
82
+ const response = await this.wroomClient.post(
83
+ this.repository,
84
+ `app/settings/integrationfields/pushcustom/${catalogId}/token`,
85
+ );
86
+
87
+ const { data: tokenData, status } = response;
88
+ if (status !== 200) {
89
+ logHttpResponse(response);
90
+ throw new Error(
91
+ `Could not create token for integration field catalog ${catalogId}`,
92
+ );
93
+ }
94
+
95
+ const token = tokenData[0];
96
+ this.tokens[catalogId] = token;
97
+
98
+ return token;
99
+ }
100
+
101
+ private async addDataToCatalog({
102
+ catalogId,
103
+ data,
104
+ }: {
105
+ catalogId: string;
106
+ data: IntegrationFieldData[];
107
+ }): Promise<void> {
108
+ const client = await this.getClient(catalogId);
109
+ const response = await client.post(
110
+ `/write/${catalogId}`,
111
+ JSON.stringify(data),
112
+ );
113
+
114
+ const { status } = response;
115
+ if (status !== 200) {
116
+ logHttpResponse(response);
117
+ throw new Error(
118
+ `Could not add data to integration field catalog ${catalogId}`,
119
+ );
120
+ }
121
+ }
122
+
123
+ private async addToCustomType({
124
+ catalogId,
125
+ customTypeId,
126
+ fieldId,
127
+ }: {
128
+ catalogId: string;
129
+ customTypeId: string;
130
+ fieldId: string;
131
+ }): Promise<void> {
132
+ const customType =
133
+ await this.customTypesApiClient.getTypeById(customTypeId);
134
+
135
+ const field = customType.json.Main[fieldId];
136
+ if (!field || field.type !== "IntegrationFields") {
137
+ throw new Error(
138
+ `Field ${fieldId} not found or is not an Integration Field`,
139
+ );
140
+ }
141
+
142
+ field.config = { ...(field.config ?? {}), catalog: catalogId };
143
+
144
+ await this.customTypesApiClient.createCustomTypes([customType]);
145
+ }
146
+
147
+ async setupIntegrationFields(
148
+ integrationFields: IntegrationFieldConfig[],
149
+ ): Promise<void> {
150
+ for (const integrationField of integrationFields) {
151
+ const catalogId = await this.addCatalog({
152
+ name: integrationField.name,
153
+ description: integrationField.description,
154
+ });
155
+ await this.addDataToCatalog({
156
+ catalogId,
157
+ data: integrationField.data,
158
+ });
159
+ await this.addToCustomType({
160
+ catalogId,
161
+ customTypeId: integrationField.customTypeId,
162
+ fieldId: integrationField.fieldId,
163
+ });
164
+ }
165
+ }
166
+ }
@@ -4,6 +4,7 @@ import { AssetApiClient } from "../clients/assetApi";
4
4
  import { AuthenticationApiClient } from "../clients/authenticationApi";
5
5
  import { CoreApiClient } from "../clients/coreApi";
6
6
  import { CustomTypesApiClient } from "../clients/customTypesApi";
7
+ import { IntegrationFieldsClient } from "../clients/integrationFields";
7
8
  import { ManageV2Client } from "../clients/manageV2";
8
9
  import { MigrationApiClient } from "../clients/migrationApi";
9
10
  import { WroomClient } from "../clients/wroom";
@@ -103,6 +104,10 @@ export class RepositoriesManager {
103
104
  customTypesApi: `${protocol}://customtypes.${url.hostname}`,
104
105
  migrationApi: `${protocol}://migration.${url.hostname}`,
105
106
  assetApi: `${protocol}://asset-api.${url.hostname}`,
107
+ integrationFieldApi:
108
+ url.hostname === "prismic.io"
109
+ ? `${protocol}://if-api.${url.hostname}/if`
110
+ : `${protocol}://api.${url.hostname}/if`, // IS THIS CORRECT FOR SQUAD ENV?
106
111
  };
107
112
  }
108
113
 
@@ -227,6 +232,13 @@ export class RepositoriesManager {
227
232
  authToken,
228
233
  repository,
229
234
  });
235
+ const integrationFieldsClient = urlConfig.integrationFieldApi
236
+ ? new IntegrationFieldsClient(urlConfig.integrationFieldApi, {
237
+ customTypesApiClient: customTypeClient,
238
+ wroomClient: this.wroomClient,
239
+ repository,
240
+ })
241
+ : undefined;
230
242
 
231
243
  return new RepositoryManager(
232
244
  repository,
@@ -237,6 +249,7 @@ export class RepositoriesManager {
237
249
  migrationApiClient,
238
250
  assetApiClient,
239
251
  this.manageV2Client,
252
+ integrationFieldsClient,
240
253
  );
241
254
  }
242
255
  }
@@ -6,6 +6,8 @@ import {
6
6
  SharedSlice,
7
7
  } from "@prismicio/types-internal/lib/customtypes";
8
8
 
9
+ import { IntegrationFieldConfig } from "../types";
10
+
9
11
  import { AssetApiClient } from "../clients/assetApi";
10
12
  import { AuthenticationApiClient } from "../clients/authenticationApi";
11
13
  import { ContentApiClient } from "../clients/contentApi";
@@ -15,6 +17,7 @@ import {
15
17
  CoreApiDocumentCreationResponse,
16
18
  } from "../clients/coreApi";
17
19
  import { CustomTypesApiClient } from "../clients/customTypesApi";
20
+ import { IntegrationFieldsClient } from "../clients/integrationFields";
18
21
  import { ManageV2Client } from "../clients/manageV2";
19
22
  import { MigrationApiClient } from "../clients/migrationApi";
20
23
  import { WroomClient } from "../clients/wroom";
@@ -32,6 +35,9 @@ export class RepositoryManager {
32
35
  private readonly migrationApiClient: MigrationApiClient | undefined,
33
36
  private readonly assetApiClient: AssetApiClient,
34
37
  private readonly manageV2Client: ManageV2Client,
38
+ private readonly integrationFieldsClient:
39
+ | IntegrationFieldsClient
40
+ | undefined,
35
41
  ) {}
36
42
 
37
43
  async configure(config: RepositoryConfig): Promise<void> {
@@ -94,6 +100,7 @@ export class RepositoryManager {
94
100
 
95
101
  if (config.integrationFields) {
96
102
  await this.toggleIntegrationFields(true);
103
+ await this.setupIntegrationFields(config.integrationFields);
97
104
  }
98
105
  }
99
106
 
@@ -745,6 +752,25 @@ export class RepositoryManager {
745
752
 
746
753
  return result;
747
754
  }
755
+
756
+ async setupIntegrationFields(
757
+ integrationFields: IntegrationFieldConfig[],
758
+ ): Promise<void> {
759
+ const profiler = logger.startTimer();
760
+
761
+ if (!this.integrationFieldsClient) {
762
+ throw new Error(
763
+ "Integration Fields client not found. Did you provide a integration fields api url in the configuration?",
764
+ );
765
+ }
766
+
767
+ await this.integrationFieldsClient.setupIntegrationFields(
768
+ integrationFields,
769
+ );
770
+ profiler.done({
771
+ message: `Integration Fields setup`,
772
+ });
773
+ }
748
774
  }
749
775
 
750
776
  export type RepositoryConfig = {
@@ -756,7 +782,7 @@ export type RepositoryConfig = {
756
782
  preview?: Preview;
757
783
  rolePerLocal?: boolean;
758
784
  customRoles?: boolean;
759
- integrationFields?: boolean;
785
+ integrationFields?: IntegrationFieldConfig[];
760
786
  };
761
787
 
762
788
  export type Preview = {
package/src/types.ts CHANGED
@@ -9,6 +9,8 @@ export type UrlConfig = {
9
9
  migrationApi?: string;
10
10
  /** Asset api base url */
11
11
  assetApi: string;
12
+ /** Integration fields api base url */
13
+ integrationFieldApi?: string;
12
14
  };
13
15
 
14
16
  export type AuthConfig = {
@@ -30,4 +32,20 @@ export type SetupConfiguration = {
30
32
  manageV2Config?: ManageV2Config;
31
33
  cluster?: string;
32
34
  environment?: string;
35
+ integrationFieldsConfig?: IntegrationFieldConfig[];
36
+ };
37
+
38
+ export type IntegrationFieldData = {
39
+ id: string;
40
+ title: string;
41
+ description: string;
42
+ blob: Record<string, unknown>;
43
+ };
44
+
45
+ export type IntegrationFieldConfig = {
46
+ name: string;
47
+ description: string;
48
+ customTypeId: string;
49
+ fieldId: string;
50
+ data: IntegrationFieldData[];
33
51
  };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Convert a string to snake_case
3
+ *
4
+ * @param str - The string to convert to snake_case
5
+ *
6
+ * @returns The snake_case string
7
+ */
8
+ export const toSnakeCase = (str: string): string => {
9
+ return str
10
+ .replace(/[\s\-]+/g, "_")
11
+ .replace(/([a-z])([A-Z])/g, "$1_$2")
12
+ .toLowerCase()
13
+ .replace(/[^a-z0-9_]/g, "")
14
+ .replace(/^_+|_+$/g, "");
15
+ };