@prismicio/e2e-tests-utils 1.4.0-alpha.2 → 1.4.1
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.
- package/README.md +16 -9
- package/dist/clients/apiClient.cjs +39 -0
- package/dist/clients/apiClient.cjs.map +1 -0
- package/dist/clients/apiClient.d.ts +30 -0
- package/dist/clients/apiClient.js +39 -0
- package/dist/clients/apiClient.js.map +1 -0
- package/dist/clients/authenticationApi.cjs +54 -34
- package/dist/clients/authenticationApi.cjs.map +1 -1
- package/dist/clients/authenticationApi.d.ts +13 -5
- package/dist/clients/authenticationApi.js +55 -35
- package/dist/clients/authenticationApi.js.map +1 -1
- package/dist/clients/contentApi.cjs +20 -50
- package/dist/clients/contentApi.cjs.map +1 -1
- package/dist/clients/contentApi.d.ts +27 -37
- package/dist/clients/contentApi.js +20 -50
- package/dist/clients/contentApi.js.map +1 -1
- package/dist/clients/coreApi.cjs +36 -31
- package/dist/clients/coreApi.cjs.map +1 -1
- package/dist/clients/coreApi.d.ts +21 -3
- package/dist/clients/coreApi.js +37 -32
- package/dist/clients/coreApi.js.map +1 -1
- package/dist/clients/customTypesApi.cjs +48 -42
- package/dist/clients/customTypesApi.cjs.map +1 -1
- package/dist/clients/customTypesApi.d.ts +34 -6
- package/dist/clients/customTypesApi.js +49 -43
- package/dist/clients/customTypesApi.js.map +1 -1
- package/dist/clients/migrationApi.cjs +30 -29
- package/dist/clients/migrationApi.cjs.map +1 -1
- package/dist/clients/migrationApi.d.ts +27 -5
- package/dist/clients/migrationApi.js +31 -30
- package/dist/clients/migrationApi.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +2 -2
- package/dist/managers/repositories.cjs +19 -9
- package/dist/managers/repositories.cjs.map +1 -1
- package/dist/managers/repositories.d.ts +2 -2
- package/dist/managers/repositories.js +23 -13
- package/dist/managers/repositories.js.map +1 -1
- package/dist/managers/repository.cjs +9 -1
- package/dist/managers/repository.cjs.map +1 -1
- package/dist/managers/repository.d.ts +6 -4
- package/dist/managers/repository.js +9 -1
- package/dist/managers/repository.js.map +1 -1
- package/dist/utils/log.cjs +4 -0
- package/dist/utils/log.cjs.map +1 -1
- package/dist/utils/log.d.ts +2 -0
- package/dist/utils/log.js +4 -0
- package/dist/utils/log.js.map +1 -1
- package/package.json +3 -1
- package/src/clients/apiClient.ts +48 -0
- package/src/clients/authenticationApi.ts +52 -50
- package/src/clients/contentApi.ts +54 -45
- package/src/clients/coreApi.ts +36 -42
- package/src/clients/customTypesApi.ts +34 -59
- package/src/clients/migrationApi.ts +36 -45
- package/src/managers/repositories.ts +26 -20
- package/src/managers/repository.ts +21 -8
- package/src/utils/log.ts +11 -0
|
@@ -1,82 +1,84 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { APIRequestContext, request } from "@playwright/test";
|
|
2
2
|
|
|
3
3
|
import { AuthConfig } from "../types";
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
export type AuthenticationClient = {
|
|
8
|
-
getToken: () => Promise<string>;
|
|
9
|
-
getMachine2MachineToken: (repository: string) => Promise<string>;
|
|
10
|
-
};
|
|
5
|
+
import { logPlaywrightApiResponse, logger } from "../utils/log";
|
|
11
6
|
|
|
12
7
|
/** Client for interacting with the authentication service to manage tokens */
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
8
|
+
export class AuthenticationApiClient {
|
|
9
|
+
private authToken?: string;
|
|
10
|
+
private _context?: APIRequestContext;
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
private readonly baseURL: string,
|
|
14
|
+
private readonly auth: AuthConfig,
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
private async getContext(): Promise<APIRequestContext> {
|
|
18
|
+
if (!this._context) {
|
|
19
|
+
this._context = await request.newContext({
|
|
20
|
+
baseURL: this.baseURL,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return this._context;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private async login(): Promise<string> {
|
|
25
28
|
const profiler = logger.startTimer();
|
|
26
29
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
const context = await this.getContext();
|
|
31
|
+
const result = await context.post("login", {
|
|
32
|
+
data: {
|
|
33
|
+
email: this.auth.email,
|
|
34
|
+
password: this.auth.password,
|
|
35
|
+
},
|
|
30
36
|
});
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
const token = await result.text();
|
|
39
|
+
if (!result.ok() || !token) {
|
|
40
|
+
logPlaywrightApiResponse(result);
|
|
34
41
|
throw new Error("Authentication failed, no token received.");
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
profiler.done({
|
|
38
|
-
message: `generated user token for ${auth.email} from auth service`,
|
|
45
|
+
message: `generated user token for ${this.auth.email} from auth service`,
|
|
39
46
|
});
|
|
40
47
|
|
|
41
|
-
return
|
|
48
|
+
return token;
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
/** Return an api user token. Creates one if needed. */
|
|
45
|
-
async
|
|
46
|
-
if (!authToken) {
|
|
47
|
-
authToken = await login();
|
|
52
|
+
async getToken(): Promise<string> {
|
|
53
|
+
if (!this.authToken) {
|
|
54
|
+
this.authToken = await this.login();
|
|
48
55
|
}
|
|
49
56
|
|
|
50
|
-
return authToken;
|
|
57
|
+
return this.authToken;
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
/** Return an api user token. Creates one if needed. */
|
|
54
|
-
async
|
|
55
|
-
if (!authToken) {
|
|
56
|
-
authToken = await login();
|
|
61
|
+
async getMachine2MachineToken(repository: string): Promise<string> {
|
|
62
|
+
if (!this.authToken) {
|
|
63
|
+
this.authToken = await this.login();
|
|
57
64
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
},
|
|
65
|
+
|
|
66
|
+
const context = await this.getContext();
|
|
67
|
+
const result = await context.get("machine2machine", {
|
|
68
|
+
headers: {
|
|
69
|
+
Authorization: `Bearer ${this.authToken}`,
|
|
70
|
+
repository,
|
|
65
71
|
},
|
|
66
|
-
);
|
|
72
|
+
});
|
|
67
73
|
|
|
68
|
-
if (!
|
|
69
|
-
|
|
74
|
+
if (!result.ok()) {
|
|
75
|
+
logPlaywrightApiResponse(result);
|
|
70
76
|
throw new Error(
|
|
71
77
|
"Machine2Machine token generation failed, no token received.",
|
|
72
78
|
);
|
|
73
79
|
}
|
|
80
|
+
const token = (await result.json()).token;
|
|
74
81
|
|
|
75
|
-
return
|
|
82
|
+
return token;
|
|
76
83
|
}
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
getToken,
|
|
80
|
-
getMachine2MachineToken,
|
|
81
|
-
};
|
|
82
|
-
};
|
|
84
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { APIResponse
|
|
1
|
+
import { APIResponse } from "@playwright/test";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import { AuthenticatedApiClient } from "./apiClient";
|
|
4
|
+
|
|
5
|
+
export interface ContentApiError {
|
|
4
6
|
type: string;
|
|
5
7
|
message: string;
|
|
6
8
|
}
|
|
7
|
-
export interface
|
|
9
|
+
export interface ContentApiSearchResponse {
|
|
8
10
|
page: number;
|
|
9
11
|
results_per_page: number;
|
|
10
12
|
results_size: number;
|
|
@@ -12,10 +14,10 @@ export interface SearchResponse {
|
|
|
12
14
|
total_pages: number;
|
|
13
15
|
next_page: string | null;
|
|
14
16
|
prev_page: string | null;
|
|
15
|
-
results:
|
|
17
|
+
results: ContentApiDocument[];
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
export interface
|
|
20
|
+
export interface ContentApiDocument {
|
|
19
21
|
id: string;
|
|
20
22
|
uid: string | null;
|
|
21
23
|
url: string | null;
|
|
@@ -32,22 +34,22 @@ export interface Document {
|
|
|
32
34
|
data: Record<string, any>;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
export interface
|
|
37
|
+
export interface ContentApiGraphQLResponse {
|
|
36
38
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
39
|
data: Record<string, any>;
|
|
38
40
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
41
|
errors?: { message: string; locations: any }[];
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
export interface
|
|
44
|
+
export interface ContentApiRef {
|
|
43
45
|
id: string;
|
|
44
46
|
ref: string;
|
|
45
47
|
label: string;
|
|
46
48
|
isMasterRef?: boolean;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
refs:
|
|
51
|
+
interface ContentApiRepoConfigResponse {
|
|
52
|
+
refs: ContentApiRef[];
|
|
51
53
|
bookmarks: Record<string, unknown>;
|
|
52
54
|
types: Record<string, string>;
|
|
53
55
|
languages: {
|
|
@@ -62,7 +64,7 @@ export interface RepoConfig {
|
|
|
62
64
|
version: string;
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
|
|
67
|
+
type SearchQueryParams = {
|
|
66
68
|
ref?: string;
|
|
67
69
|
query?: string;
|
|
68
70
|
q?: string;
|
|
@@ -80,18 +82,22 @@ type ApiVersions = "v1" | "v2";
|
|
|
80
82
|
|
|
81
83
|
/**
|
|
82
84
|
* Client to query the Prismic content api. Uses Playwright to benefit from
|
|
83
|
-
* network request traces in your reports.
|
|
84
|
-
* used but had too many abstractions (caching, error handling) that we didn't
|
|
85
|
-
* want for test execution. See api docs:
|
|
85
|
+
* network request traces in your reports. See api docs:
|
|
86
86
|
* https://prismic.io/docs/rest-api-technical-reference
|
|
87
87
|
*/
|
|
88
|
-
export class ContentApiClient {
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
export class ContentApiClient extends AuthenticatedApiClient {
|
|
89
|
+
private version: ApiVersions;
|
|
90
|
+
private accessToken: string | undefined;
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
|
-
* @example
|
|
94
|
-
*
|
|
93
|
+
* @example To instantiate the class:
|
|
94
|
+
*
|
|
95
|
+
* ```js
|
|
96
|
+
* new ContentApiClient("https://my-repo.cdn.prismic.io", {
|
|
97
|
+
* version: "v2",
|
|
98
|
+
* accessToken: "my-secret-token",
|
|
99
|
+
* });
|
|
100
|
+
* ```
|
|
95
101
|
*
|
|
96
102
|
* @param baseURL - the api base URL like https://my-repo.cdn.prismic.io
|
|
97
103
|
* @param config - Optional configuration
|
|
@@ -101,30 +107,25 @@ export class ContentApiClient {
|
|
|
101
107
|
* https://prismic.io/docs/access-token
|
|
102
108
|
*/
|
|
103
109
|
constructor(
|
|
104
|
-
|
|
110
|
+
baseURL: string,
|
|
105
111
|
config: { version?: ApiVersions; accessToken?: string } = {},
|
|
106
112
|
) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
baseURL: this.baseURL,
|
|
114
|
-
// reset any Authorization header set globally with Playwright
|
|
115
|
-
// didn't find a way to delete it
|
|
116
|
-
extraHTTPHeaders: { Authorization: "" },
|
|
117
|
-
});
|
|
113
|
+
// Use an empty string as Authorization header in case it is already set globally in the project Playwright config file.
|
|
114
|
+
// This is because the content api returns an error in case it gets an non-empty invalid Authorization
|
|
115
|
+
// even though it actually checks authorization from the access_token query parameter.
|
|
116
|
+
super(baseURL, config.accessToken || "");
|
|
117
|
+
this.version = config.version || "v2";
|
|
118
|
+
this.accessToken = config.accessToken;
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
async get(
|
|
121
122
|
path: string,
|
|
122
|
-
params?:
|
|
123
|
+
params?: SearchQueryParams,
|
|
123
124
|
headers?: Record<string, string>,
|
|
124
125
|
): Promise<APIResponse> {
|
|
125
|
-
const context = await this
|
|
126
|
+
const context = await this.getContext();
|
|
126
127
|
const securityParams = {
|
|
127
|
-
...(this
|
|
128
|
+
...(this.accessToken ? { access_token: this.accessToken } : {}),
|
|
128
129
|
};
|
|
129
130
|
|
|
130
131
|
return context.get(path, {
|
|
@@ -135,7 +136,7 @@ export class ContentApiClient {
|
|
|
135
136
|
|
|
136
137
|
async getAsJson<T>(
|
|
137
138
|
url: string,
|
|
138
|
-
params?:
|
|
139
|
+
params?: SearchQueryParams,
|
|
139
140
|
headers?: Record<string, string>,
|
|
140
141
|
): Promise<T> {
|
|
141
142
|
const response = await this.get(url, params, headers);
|
|
@@ -144,16 +145,21 @@ export class ContentApiClient {
|
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
/** Query the graphql api - https://prismic.io/docs/graphql-technical-reference */
|
|
147
|
-
async graphql(
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
async graphql(
|
|
149
|
+
ref: string,
|
|
150
|
+
query: string,
|
|
151
|
+
): Promise<ContentApiGraphQLResponse> {
|
|
152
|
+
return this.getAsJson<ContentApiGraphQLResponse>(
|
|
153
|
+
"graphql",
|
|
150
154
|
{ query },
|
|
151
155
|
{ "Prismic-ref": ref },
|
|
152
156
|
);
|
|
153
157
|
}
|
|
154
158
|
|
|
155
|
-
async getRefs(): Promise<
|
|
156
|
-
const data = await this.getAsJson<
|
|
159
|
+
async getRefs(): Promise<ContentApiRef[]> {
|
|
160
|
+
const data = await this.getAsJson<ContentApiRepoConfigResponse>(
|
|
161
|
+
`api/${this.version}`,
|
|
162
|
+
);
|
|
157
163
|
|
|
158
164
|
return data.refs;
|
|
159
165
|
}
|
|
@@ -180,14 +186,14 @@ export class ContentApiClient {
|
|
|
180
186
|
}
|
|
181
187
|
|
|
182
188
|
/** Search documents from the `/api/v<version>/documents/search` endpoint. */
|
|
183
|
-
async search(filters?:
|
|
189
|
+
async search(filters?: SearchQueryParams): Promise<ContentApiSearchResponse> {
|
|
184
190
|
let ref = filters?.ref;
|
|
185
191
|
if (!ref) {
|
|
186
192
|
ref = await this.getMasterRef();
|
|
187
193
|
}
|
|
188
194
|
|
|
189
|
-
return this.getAsJson<
|
|
190
|
-
|
|
195
|
+
return this.getAsJson<ContentApiSearchResponse>(
|
|
196
|
+
`api/${this.version}/documents/search`,
|
|
191
197
|
{
|
|
192
198
|
...filters,
|
|
193
199
|
ref,
|
|
@@ -199,15 +205,18 @@ export class ContentApiClient {
|
|
|
199
205
|
* Search for a single document by its it, using the
|
|
200
206
|
* `/api/v<version>/documents/search` endpoint and a default filter.
|
|
201
207
|
*/
|
|
202
|
-
async searchByID(
|
|
208
|
+
async searchByID(
|
|
209
|
+
id: string,
|
|
210
|
+
filters?: SearchQueryParams,
|
|
211
|
+
): Promise<ContentApiSearchResponse> {
|
|
203
212
|
return this.search({ ...filters, q: `[[at(document.id, "${id}")]]` });
|
|
204
213
|
}
|
|
205
214
|
|
|
206
215
|
/** Retrieve a single document or undefined if not found. */
|
|
207
216
|
async getDocumentByID(
|
|
208
217
|
id: string,
|
|
209
|
-
filters?:
|
|
210
|
-
): Promise<
|
|
218
|
+
filters?: SearchQueryParams,
|
|
219
|
+
): Promise<ContentApiDocument | undefined> {
|
|
211
220
|
const data = await this.searchByID(id, filters);
|
|
212
221
|
switch (data.results_size) {
|
|
213
222
|
case 0:
|
package/src/clients/coreApi.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { logPlaywrightApiResponse, logger } from "../utils/log";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import { AuthenticationClient } from "./authenticationApi";
|
|
3
|
+
import { AuthServerToken, AuthenticatedApiClient } from "./apiClient";
|
|
6
4
|
|
|
7
5
|
type Language = {
|
|
8
6
|
id: string;
|
|
@@ -15,56 +13,52 @@ export type CoreClient = {
|
|
|
15
13
|
publishDraft(documentId: string): Promise<void>;
|
|
16
14
|
};
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
16
|
+
export class CoreApiClient extends AuthenticatedApiClient {
|
|
17
|
+
/**
|
|
18
|
+
* @example To instantiate the class:
|
|
19
|
+
*
|
|
20
|
+
* ```js
|
|
21
|
+
* new CoreApiClient("https://my-repo.prismic.io", {
|
|
22
|
+
* authToken: "my-secret-token",
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @param baseURL - the api base URL like https://my-repo.prismic.io
|
|
27
|
+
* @param config - Optional configuration
|
|
28
|
+
*
|
|
29
|
+
* - {@link config.authToken}: Api token generated from the auth service or a
|
|
30
|
+
* function to fetch it when it's needed.
|
|
31
|
+
*/
|
|
32
|
+
constructor(baseURL: string, config: AuthServerToken) {
|
|
33
|
+
super(baseURL, config);
|
|
34
|
+
}
|
|
38
35
|
|
|
39
|
-
async
|
|
36
|
+
async getLanguages(): Promise<Language[]> {
|
|
40
37
|
const profiler = logger.startTimer();
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
);
|
|
38
|
+
const context = await this.getContext();
|
|
39
|
+
const result = await context.get("core/repository");
|
|
44
40
|
|
|
45
|
-
if (200 !== result.status || !result.
|
|
46
|
-
|
|
41
|
+
if (200 !== result.status() || !(await result.json()).languages) {
|
|
42
|
+
await logPlaywrightApiResponse(result);
|
|
47
43
|
throw new Error("Could not get languages from the core api.");
|
|
48
44
|
}
|
|
49
45
|
|
|
50
46
|
profiler.done({ message: "retrieved languages configuration" });
|
|
51
47
|
|
|
52
|
-
return result.
|
|
48
|
+
return (await result.json()).languages;
|
|
53
49
|
}
|
|
54
50
|
|
|
55
|
-
async
|
|
56
|
-
const
|
|
57
|
-
|
|
51
|
+
async publishDraft(documentId: string): Promise<void> {
|
|
52
|
+
const context = await this.getContext();
|
|
53
|
+
const result = await context.patch(`core/documents/${documentId}/draft`, {
|
|
54
|
+
data: {
|
|
55
|
+
status: "published",
|
|
56
|
+
},
|
|
58
57
|
});
|
|
59
58
|
|
|
60
|
-
if (204 !== result.status) {
|
|
61
|
-
|
|
59
|
+
if (204 !== result.status()) {
|
|
60
|
+
await logPlaywrightApiResponse(result);
|
|
62
61
|
throw new Error(`Could not publish document with id ${documentId}`);
|
|
63
62
|
}
|
|
64
63
|
}
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
getLanguages,
|
|
68
|
-
publishDraft,
|
|
69
|
-
};
|
|
70
|
-
};
|
|
64
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import axios, { AxiosInstance } from "axios";
|
|
2
1
|
import isEqual from "lodash.isequal";
|
|
3
2
|
|
|
4
3
|
import {
|
|
@@ -6,46 +5,25 @@ import {
|
|
|
6
5
|
SharedSlice,
|
|
7
6
|
} from "@prismicio/types-internal/lib/customtypes";
|
|
8
7
|
|
|
9
|
-
import {
|
|
8
|
+
import { logPlaywrightApiResponse, logger } from "../utils/log";
|
|
10
9
|
|
|
11
|
-
import {
|
|
10
|
+
import { AuthServerToken, AuthenticatedApiClient } from "./apiClient";
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
};
|
|
12
|
+
type ItemType = CustomType | SharedSlice;
|
|
13
|
+
type ItemTypePath = "customtypes" | "slices";
|
|
14
|
+
type ItemOperation = "insert" | "update";
|
|
17
15
|
|
|
18
16
|
/**
|
|
19
17
|
* Client for interacting with the Custom Types API to create/update custom
|
|
20
18
|
* types and slices.
|
|
21
19
|
*/
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
type ItemOperation = "insert" | "update";
|
|
30
|
-
|
|
31
|
-
const client: AxiosInstance = axios.create({
|
|
32
|
-
baseURL,
|
|
33
|
-
validateStatus: () => true, // Don't throw on 4XX errors
|
|
34
|
-
headers: {
|
|
35
|
-
repository,
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// Add an interceptor to authenticate requests
|
|
40
|
-
client.interceptors.request.use(async (config) => {
|
|
41
|
-
const auth = "Authorization";
|
|
42
|
-
if (!config.headers[auth]) {
|
|
43
|
-
const token = await authClient.getToken();
|
|
44
|
-
config.headers[auth] = `Bearer ${token}`;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return config;
|
|
48
|
-
});
|
|
20
|
+
export class CustomTypesApiClient extends AuthenticatedApiClient {
|
|
21
|
+
constructor(
|
|
22
|
+
baseURL: string,
|
|
23
|
+
config: { authToken: AuthServerToken; repository: string },
|
|
24
|
+
) {
|
|
25
|
+
super(baseURL, config.authToken, { repository: config.repository });
|
|
26
|
+
}
|
|
49
27
|
|
|
50
28
|
/**
|
|
51
29
|
* Create or update a custom type or slice.
|
|
@@ -57,7 +35,7 @@ export const createCustomTypesApiClient = (
|
|
|
57
35
|
* @throws Error if the item status cannot be retrieved or the item cannot be
|
|
58
36
|
* created/updated.
|
|
59
37
|
*/
|
|
60
|
-
async
|
|
38
|
+
private async upsert(
|
|
61
39
|
endpoint: ItemTypePath,
|
|
62
40
|
operation: ItemOperation,
|
|
63
41
|
data: ItemType,
|
|
@@ -65,9 +43,10 @@ export const createCustomTypesApiClient = (
|
|
|
65
43
|
const profiler = logger.startTimer();
|
|
66
44
|
const path = `${endpoint}/${operation}`;
|
|
67
45
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
46
|
+
const context = await this.getContext();
|
|
47
|
+
const result = await context.post(path, { data });
|
|
48
|
+
if (!result.ok()) {
|
|
49
|
+
logPlaywrightApiResponse(result);
|
|
71
50
|
throw new Error(`Could not ${operation} item`);
|
|
72
51
|
}
|
|
73
52
|
profiler.done({
|
|
@@ -75,20 +54,21 @@ export const createCustomTypesApiClient = (
|
|
|
75
54
|
});
|
|
76
55
|
}
|
|
77
56
|
|
|
78
|
-
async
|
|
57
|
+
private async getRemoteItems(
|
|
79
58
|
endpoint: ItemTypePath,
|
|
80
59
|
): Promise<CustomType[] | SharedSlice[]> {
|
|
81
|
-
const
|
|
60
|
+
const context = await this.getContext();
|
|
61
|
+
const result = await context.get(endpoint);
|
|
82
62
|
|
|
83
|
-
if (!
|
|
84
|
-
|
|
63
|
+
if (!result.ok()) {
|
|
64
|
+
logPlaywrightApiResponse(result);
|
|
85
65
|
throw new Error("Could not get items status from the Custom Type api.");
|
|
86
66
|
}
|
|
87
67
|
|
|
88
|
-
return result.
|
|
68
|
+
return result.json();
|
|
89
69
|
}
|
|
90
70
|
|
|
91
|
-
async
|
|
71
|
+
private async getDifference(
|
|
92
72
|
remoteItems: CustomType[] | SharedSlice[],
|
|
93
73
|
local: ItemType,
|
|
94
74
|
): Promise<ItemOperation | undefined> {
|
|
@@ -106,16 +86,16 @@ export const createCustomTypesApiClient = (
|
|
|
106
86
|
}
|
|
107
87
|
|
|
108
88
|
/** Create items only if they have changed compared to their remote status */
|
|
109
|
-
async
|
|
89
|
+
private async upsertIfChanged(
|
|
110
90
|
itemType: ItemTypePath,
|
|
111
91
|
localItems: ItemType[] = [],
|
|
112
|
-
) {
|
|
113
|
-
const remoteItems = await getRemoteItems(itemType);
|
|
92
|
+
): Promise<void> {
|
|
93
|
+
const remoteItems = await this.getRemoteItems(itemType);
|
|
114
94
|
await Promise.all(
|
|
115
95
|
localItems.map(async (localItem) => {
|
|
116
|
-
const operation = await getDifference(remoteItems, localItem);
|
|
96
|
+
const operation = await this.getDifference(remoteItems, localItem);
|
|
117
97
|
|
|
118
|
-
return operation && upsert(itemType, operation, localItem);
|
|
98
|
+
return operation && this.upsert(itemType, operation, localItem);
|
|
119
99
|
}),
|
|
120
100
|
);
|
|
121
101
|
}
|
|
@@ -125,8 +105,8 @@ export const createCustomTypesApiClient = (
|
|
|
125
105
|
*
|
|
126
106
|
* @param customTypes -
|
|
127
107
|
*/
|
|
128
|
-
async
|
|
129
|
-
await upsertIfChanged("customtypes", customTypes);
|
|
108
|
+
async createCustomTypes(customTypes: CustomType[] = []): Promise<void> {
|
|
109
|
+
await this.upsertIfChanged("customtypes", customTypes);
|
|
130
110
|
}
|
|
131
111
|
|
|
132
112
|
/**
|
|
@@ -134,12 +114,7 @@ export const createCustomTypesApiClient = (
|
|
|
134
114
|
*
|
|
135
115
|
* @param slices -
|
|
136
116
|
*/
|
|
137
|
-
async
|
|
138
|
-
await upsertIfChanged("slices", slices);
|
|
117
|
+
async createSlices(slices: SharedSlice[] = []): Promise<void> {
|
|
118
|
+
await this.upsertIfChanged("slices", slices);
|
|
139
119
|
}
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
createCustomTypes,
|
|
143
|
-
createSlices,
|
|
144
|
-
};
|
|
145
|
-
};
|
|
120
|
+
}
|