@aws-amplify/amplify-util-uibuilder 1.9.0-replace-lambda-callouts-branch.0 → 1.9.0
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/CHANGELOG.md +40 -9
- package/lib/clients/amplify-studio-client.d.ts +5 -1
- package/lib/clients/amplify-studio-client.d.ts.map +1 -1
- package/lib/clients/amplify-studio-client.js +54 -8
- package/lib/clients/amplify-studio-client.js.map +1 -1
- package/lib/commands/generateComponents.d.ts.map +1 -1
- package/lib/commands/generateComponents.js +33 -34
- package/lib/commands/generateComponents.js.map +1 -1
- package/lib/commands/utils/codegenResources.d.ts +1 -15
- package/lib/commands/utils/codegenResources.d.ts.map +1 -1
- package/lib/commands/utils/codegenResources.js +1 -122
- package/lib/commands/utils/codegenResources.js.map +1 -1
- package/lib/commands/utils/detachedFormCleanup.d.ts +3 -4
- package/lib/commands/utils/detachedFormCleanup.d.ts.map +1 -1
- package/lib/commands/utils/detachedFormCleanup.js.map +1 -1
- package/lib/commands/utils/storageManager.d.ts +3 -4
- package/lib/commands/utils/storageManager.d.ts.map +1 -1
- package/lib/commands/utils/storageManager.js +1 -5
- package/lib/commands/utils/storageManager.js.map +1 -1
- package/lib/commands/utils/syncAmplifyUiBuilderComponents.d.ts +8 -16
- package/lib/commands/utils/syncAmplifyUiBuilderComponents.d.ts.map +1 -1
- package/lib/commands/utils/syncAmplifyUiBuilderComponents.js +186 -74
- package/lib/commands/utils/syncAmplifyUiBuilderComponents.js.map +1 -1
- package/package.json +28 -19
- package/src/__tests__/__snapshots__/syncAmplifyUiComponents.test.ts.snap +46 -0
- package/src/__tests__/cloneComponentsFromEnv.test.ts +8 -0
- package/src/__tests__/detachedFormCleanup.test.ts +7 -5
- package/src/__tests__/generateComponents.test.ts +187 -15
- package/src/__tests__/getAmplifyDataSchema.test.ts +1 -2
- package/src/__tests__/prePushHandler.test.ts +7 -0
- package/src/__tests__/storageManager.test.ts +7 -4
- package/src/__tests__/syncAmplifyUiComponents.test.ts +106 -95
- package/src/clients/amplify-studio-client.ts +56 -9
- package/src/commands/generateComponents.ts +45 -56
- package/src/commands/utils/codegenResources.ts +1 -225
- package/src/commands/utils/detachedFormCleanup.ts +3 -4
- package/src/commands/utils/storageManager.ts +3 -7
- package/src/commands/utils/syncAmplifyUiBuilderComponents.ts +210 -123
- package/tsconfig.tsbuildinfo +1 -1
- package/src/__tests__/createUiBuilderComponent.test.ts +0 -90
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
import aws from 'aws-sdk'; // eslint-disable-line import/no-extraneous-dependencies
|
|
2
2
|
import * as utils from '../commands/utils';
|
|
3
3
|
import { run } from '../commands/generateComponents';
|
|
4
|
+
import { isDataStoreEnabled } from '@aws-amplify/amplify-category-api';
|
|
5
|
+
import { getTransformerVersion } from '../commands/utils/featureFlags';
|
|
4
6
|
|
|
5
7
|
jest.mock('../commands/utils');
|
|
6
8
|
jest.mock('@aws-amplify/amplify-cli-core');
|
|
9
|
+
jest.mock('@aws-amplify/amplify-category-api', () => ({
|
|
10
|
+
...jest.requireActual('@aws-amplify/amplify-category-api'),
|
|
11
|
+
isDataStoreEnabled: jest.fn(),
|
|
12
|
+
}));
|
|
13
|
+
jest.mock('../commands/utils/featureFlags', () => ({
|
|
14
|
+
...jest.requireActual('../commands/utils/featureFlags'),
|
|
15
|
+
getTransformerVersion: jest.fn(),
|
|
16
|
+
}));
|
|
7
17
|
const awsMock = aws as any;
|
|
8
18
|
const utilsMock = utils as any;
|
|
9
19
|
|
|
20
|
+
const isDataStoreEnabledMocked = jest.mocked(isDataStoreEnabled);
|
|
21
|
+
const getTransformerVersionMocked = jest.mocked(getTransformerVersion);
|
|
10
22
|
utilsMock.shouldRenderComponents = jest.fn().mockReturnValue(true);
|
|
11
23
|
utilsMock.notifyMissingPackages = jest.fn().mockReturnValue(true);
|
|
12
24
|
utilsMock.getAmplifyDataSchema = jest.fn().mockReturnValue({});
|
|
25
|
+
utilsMock.isFormDetachedFromModel = jest.fn().mockReturnValue(false);
|
|
26
|
+
utilsMock.extractUIComponents = jest.fn().mockReturnValue(undefined);
|
|
27
|
+
utilsMock.waitForSucceededJob = jest
|
|
28
|
+
.fn()
|
|
29
|
+
.mockReturnValue({ asset: { downloadUrl: 'amazon.com' }, statusMessage: `{\"codegenErrors\": [{\"schemaName\": \"BlogUpdateForm\"}]}` });
|
|
13
30
|
|
|
14
31
|
jest.mock('../commands/utils/featureFlags', () => ({
|
|
15
32
|
getTransformerVersion: jest.fn().mockReturnValue(2),
|
|
@@ -19,7 +36,25 @@ describe('can generate components', () => {
|
|
|
19
36
|
let context: any;
|
|
20
37
|
let schemas: any;
|
|
21
38
|
let mockedExport: jest.Mock<any, any>;
|
|
39
|
+
const getMetadataPromise = jest.fn().mockReturnValue({
|
|
40
|
+
features: {
|
|
41
|
+
autoGenerateForms: 'true',
|
|
42
|
+
autoGenerateViews: 'true',
|
|
43
|
+
formFeatureFlags: {
|
|
44
|
+
isRelationshipSupported: 'false',
|
|
45
|
+
isNonModelSupported: 'false',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
const startCodegenJobPromise = jest.fn().mockReturnValue({
|
|
50
|
+
entity: { id: 'jobId123' },
|
|
51
|
+
});
|
|
52
|
+
const mockStartCodegenJob = jest.fn().mockReturnValue({
|
|
53
|
+
promise: startCodegenJobPromise,
|
|
54
|
+
});
|
|
22
55
|
beforeEach(() => {
|
|
56
|
+
isDataStoreEnabledMocked.mockResolvedValue(true);
|
|
57
|
+
getTransformerVersionMocked.mockResolvedValue(2);
|
|
23
58
|
context = {
|
|
24
59
|
amplify: {
|
|
25
60
|
invokePluginMethod: () => ({}),
|
|
@@ -34,13 +69,11 @@ describe('can generate components', () => {
|
|
|
34
69
|
schemas = {
|
|
35
70
|
entities: [
|
|
36
71
|
{
|
|
37
|
-
resultType: 'SUCCESS',
|
|
38
72
|
schemaName: 'testSchema',
|
|
39
73
|
name: 'testSchema',
|
|
40
74
|
schemaVersion: '1.0',
|
|
41
75
|
},
|
|
42
76
|
{
|
|
43
|
-
resultType: 'FAILURE',
|
|
44
77
|
schemaName: 'testSchema',
|
|
45
78
|
name: 'testSchema',
|
|
46
79
|
schemaVersion: '1.0',
|
|
@@ -65,16 +98,11 @@ describe('can generate components', () => {
|
|
|
65
98
|
promise: () => mockedExport(),
|
|
66
99
|
}),
|
|
67
100
|
getMetadata: jest.fn().mockReturnValue({
|
|
68
|
-
promise:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
isRelationshipSupported: 'false',
|
|
74
|
-
isNonModelSupported: 'false',
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
}),
|
|
101
|
+
promise: getMetadataPromise,
|
|
102
|
+
}),
|
|
103
|
+
startCodegenJob: mockStartCodegenJob,
|
|
104
|
+
getCodegenJob: jest.fn().mockReturnValue({
|
|
105
|
+
promise: jest.fn().mockReturnValue({ status: 'succeeded' }),
|
|
78
106
|
}),
|
|
79
107
|
});
|
|
80
108
|
utilsMock.generateUiBuilderComponents = jest.fn().mockReturnValue(schemas.entities);
|
|
@@ -87,11 +115,155 @@ describe('can generate components', () => {
|
|
|
87
115
|
});
|
|
88
116
|
|
|
89
117
|
it('runs generateComponents', async () => {
|
|
118
|
+
utilsMock.isFormDetachedFromModel = jest.fn().mockReturnValueOnce(true);
|
|
90
119
|
await run(context, 'PostPull');
|
|
91
120
|
expect(mockedExport).toBeCalledTimes(3);
|
|
92
|
-
expect(
|
|
93
|
-
expect(utilsMock.
|
|
94
|
-
expect(utilsMock.
|
|
121
|
+
expect(startCodegenJobPromise).toBeCalledTimes(1);
|
|
122
|
+
expect(utilsMock.waitForSucceededJob).toBeCalledTimes(1);
|
|
123
|
+
expect(utilsMock.getUiBuilderComponentsPath).toBeCalledTimes(1);
|
|
124
|
+
expect(utilsMock.extractUIComponents).toBeCalledTimes(1);
|
|
95
125
|
expect(utilsMock.deleteDetachedForms).toBeCalledTimes(1);
|
|
96
126
|
});
|
|
127
|
+
|
|
128
|
+
it('should autogenerate forms if transformer v2 and datastore and feature flag are enabled', async () => {
|
|
129
|
+
isDataStoreEnabledMocked.mockResolvedValue(true);
|
|
130
|
+
getTransformerVersionMocked.mockResolvedValue(2);
|
|
131
|
+
getMetadataPromise.mockReturnValue({
|
|
132
|
+
features: {
|
|
133
|
+
autoGenerateForms: 'true',
|
|
134
|
+
autoGenerateViews: 'true',
|
|
135
|
+
formFeatureFlags: {
|
|
136
|
+
isRelationshipSupported: 'false',
|
|
137
|
+
isNonModelSupported: 'false',
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
await run(context, 'PostPull');
|
|
142
|
+
expect(mockStartCodegenJob).toHaveBeenCalledWith({
|
|
143
|
+
appId: 'testAppId',
|
|
144
|
+
environmentName: 'testEnvName',
|
|
145
|
+
codegenJobToCreate: {
|
|
146
|
+
renderConfig: {
|
|
147
|
+
react: {
|
|
148
|
+
module: 'es2020',
|
|
149
|
+
target: 'es2020',
|
|
150
|
+
script: 'jsx',
|
|
151
|
+
renderTypeDeclarations: true,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
genericDataSchema: undefined,
|
|
155
|
+
autoGenerateForms: true,
|
|
156
|
+
features: {
|
|
157
|
+
isNonModelSupported: false,
|
|
158
|
+
isRelationshipSupported: false,
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should not autogenerate forms if transformer v1', async () => {
|
|
165
|
+
isDataStoreEnabledMocked.mockResolvedValue(true);
|
|
166
|
+
getTransformerVersionMocked.mockResolvedValue(1);
|
|
167
|
+
getMetadataPromise.mockReturnValue({
|
|
168
|
+
features: {
|
|
169
|
+
autoGenerateForms: 'true',
|
|
170
|
+
autoGenerateViews: 'true',
|
|
171
|
+
formFeatureFlags: {
|
|
172
|
+
isRelationshipSupported: 'false',
|
|
173
|
+
isNonModelSupported: 'false',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
await run(context, 'PostPull');
|
|
178
|
+
expect(mockStartCodegenJob).toHaveBeenCalledWith({
|
|
179
|
+
appId: 'testAppId',
|
|
180
|
+
environmentName: 'testEnvName',
|
|
181
|
+
codegenJobToCreate: {
|
|
182
|
+
renderConfig: {
|
|
183
|
+
react: {
|
|
184
|
+
module: 'es2020',
|
|
185
|
+
target: 'es2020',
|
|
186
|
+
script: 'jsx',
|
|
187
|
+
renderTypeDeclarations: true,
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
genericDataSchema: undefined,
|
|
191
|
+
autoGenerateForms: false,
|
|
192
|
+
features: {
|
|
193
|
+
isNonModelSupported: false,
|
|
194
|
+
isRelationshipSupported: false,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should not autogenerate forms if datastore is not enabled', async () => {
|
|
201
|
+
isDataStoreEnabledMocked.mockResolvedValue(false);
|
|
202
|
+
getMetadataPromise.mockReturnValue({
|
|
203
|
+
features: {
|
|
204
|
+
autoGenerateForms: 'true',
|
|
205
|
+
autoGenerateViews: 'true',
|
|
206
|
+
formFeatureFlags: {
|
|
207
|
+
isRelationshipSupported: 'false',
|
|
208
|
+
isNonModelSupported: 'false',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
await run(context, 'PostPull');
|
|
213
|
+
expect(mockStartCodegenJob).toHaveBeenCalledWith({
|
|
214
|
+
appId: 'testAppId',
|
|
215
|
+
environmentName: 'testEnvName',
|
|
216
|
+
codegenJobToCreate: {
|
|
217
|
+
renderConfig: {
|
|
218
|
+
react: {
|
|
219
|
+
module: 'es2020',
|
|
220
|
+
target: 'es2020',
|
|
221
|
+
script: 'jsx',
|
|
222
|
+
renderTypeDeclarations: true,
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
genericDataSchema: undefined,
|
|
226
|
+
autoGenerateForms: false,
|
|
227
|
+
features: {
|
|
228
|
+
isNonModelSupported: false,
|
|
229
|
+
isRelationshipSupported: false,
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('should not autogenerate forms if feature flag is not enabled', async () => {
|
|
236
|
+
isDataStoreEnabledMocked.mockResolvedValue(true);
|
|
237
|
+
getMetadataPromise.mockReturnValue({
|
|
238
|
+
features: {
|
|
239
|
+
autoGenerateForms: 'false',
|
|
240
|
+
autoGenerateViews: 'true',
|
|
241
|
+
formFeatureFlags: {
|
|
242
|
+
isRelationshipSupported: 'false',
|
|
243
|
+
isNonModelSupported: 'false',
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
await run(context, 'PostPull');
|
|
248
|
+
expect(mockStartCodegenJob).toHaveBeenCalledWith({
|
|
249
|
+
appId: 'testAppId',
|
|
250
|
+
environmentName: 'testEnvName',
|
|
251
|
+
codegenJobToCreate: {
|
|
252
|
+
renderConfig: {
|
|
253
|
+
react: {
|
|
254
|
+
module: 'es2020',
|
|
255
|
+
target: 'es2020',
|
|
256
|
+
script: 'jsx',
|
|
257
|
+
renderTypeDeclarations: true,
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
genericDataSchema: undefined,
|
|
261
|
+
autoGenerateForms: false,
|
|
262
|
+
features: {
|
|
263
|
+
isNonModelSupported: false,
|
|
264
|
+
isRelationshipSupported: false,
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
});
|
|
97
269
|
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { printer } from '@aws-amplify/amplify-prompts'; // eslint-disable-line import/no-extraneous-dependencies
|
|
2
|
-
import { mocked } from 'ts-jest/utils';
|
|
3
2
|
import { getAmplifyDataSchema } from '../commands/utils';
|
|
4
3
|
|
|
5
4
|
jest.mock('@aws-amplify/amplify-prompts');
|
|
6
5
|
|
|
7
|
-
const printerMock = mocked(printer);
|
|
6
|
+
const printerMock = jest.mocked(printer);
|
|
8
7
|
|
|
9
8
|
const sampleIntrospectionSchema = {
|
|
10
9
|
version: 1,
|
|
@@ -4,15 +4,21 @@ import { Form } from 'aws-sdk/clients/amplifyuibuilder'; // eslint-disable-line
|
|
|
4
4
|
import { printer } from '@aws-amplify/amplify-prompts'; // eslint-disable-line import/no-extraneous-dependencies
|
|
5
5
|
import * as utils from '../commands/utils';
|
|
6
6
|
import { prePushHandler } from '../utils/prePushHandler';
|
|
7
|
+
import { isDataStoreEnabled } from '@aws-amplify/amplify-category-api';
|
|
7
8
|
|
|
8
9
|
jest.mock('../commands/utils');
|
|
9
10
|
jest.mock('@aws-amplify/amplify-cli-core');
|
|
10
11
|
jest.mock('../commands/utils/featureFlags', () => ({
|
|
11
12
|
getTransformerVersion: jest.fn().mockImplementation(() => 2),
|
|
12
13
|
}));
|
|
14
|
+
jest.mock('@aws-amplify/amplify-category-api', () => ({
|
|
15
|
+
...jest.requireActual('@aws-amplify/amplify-category-api'),
|
|
16
|
+
isDataStoreEnabled: jest.fn(),
|
|
17
|
+
}));
|
|
13
18
|
|
|
14
19
|
const awsMock = aws as any;
|
|
15
20
|
const utilsMock = utils as any;
|
|
21
|
+
const isDataStoreEnabledMocked = jest.mocked(isDataStoreEnabled);
|
|
16
22
|
|
|
17
23
|
utilsMock.shouldRenderComponents = jest.fn().mockImplementation(() => true);
|
|
18
24
|
|
|
@@ -22,6 +28,7 @@ describe('handlePrePush', () => {
|
|
|
22
28
|
let exportedForms: Form[];
|
|
23
29
|
|
|
24
30
|
beforeEach(() => {
|
|
31
|
+
isDataStoreEnabledMocked.mockResolvedValue(true);
|
|
25
32
|
context = {
|
|
26
33
|
amplify: {
|
|
27
34
|
invokePluginMethod: jest.fn().mockResolvedValue({ models: { Comment: {} } }),
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { StudioSchema } from '@aws-amplify/codegen-ui';
|
|
2
1
|
import { hasStorageField } from '../commands/utils';
|
|
2
|
+
import { Form } from 'aws-sdk/clients/amplifyuibuilder';
|
|
3
3
|
|
|
4
|
-
const formWithNoCustomization:
|
|
4
|
+
const formWithNoCustomization: Form = {
|
|
5
5
|
id: 'f-123456',
|
|
6
|
+
appId: '123',
|
|
7
|
+
environmentName: 'staging',
|
|
8
|
+
schemaVersion: '1.0',
|
|
6
9
|
name: 'BlogCreateForm',
|
|
7
10
|
formActionType: 'create',
|
|
8
11
|
dataType: {
|
|
@@ -15,7 +18,7 @@ const formWithNoCustomization: StudioSchema = {
|
|
|
15
18
|
cta: {},
|
|
16
19
|
};
|
|
17
20
|
|
|
18
|
-
const formWithNoStorageField:
|
|
21
|
+
const formWithNoStorageField: Form = {
|
|
19
22
|
...formWithNoCustomization,
|
|
20
23
|
dataType: { dataSourceType: 'Custom', dataTypeName: 'Blog' },
|
|
21
24
|
fields: {
|
|
@@ -23,7 +26,7 @@ const formWithNoStorageField: StudioSchema = {
|
|
|
23
26
|
},
|
|
24
27
|
};
|
|
25
28
|
|
|
26
|
-
const formWithStorageField:
|
|
29
|
+
const formWithStorageField: Form = {
|
|
27
30
|
...formWithNoCustomization,
|
|
28
31
|
dataType: { dataSourceType: 'Custom', dataTypeName: 'Blog' },
|
|
29
32
|
fields: {
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import aws from 'aws-sdk'; // eslint-disable-line import/no-extraneous-dependencies
|
|
1
|
+
import { AmplifyCategories, AmplifySupportedService, stateManager } from '@aws-amplify/amplify-cli-core';
|
|
2
|
+
import aws from 'aws-sdk';
|
|
4
3
|
import {
|
|
5
|
-
generateUiBuilderComponents,
|
|
6
|
-
generateUiBuilderThemes,
|
|
7
4
|
getEnvName,
|
|
8
5
|
getAppId,
|
|
9
6
|
resolveAppId,
|
|
10
|
-
|
|
7
|
+
mapGenericDataSchemaToCodegen,
|
|
8
|
+
waitForSucceededJob,
|
|
9
|
+
extractUIComponents,
|
|
10
|
+
fetchWithRetries,
|
|
11
11
|
} from '../commands/utils';
|
|
12
12
|
import { AmplifyStudioClient } from '../clients';
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
13
|
+
import { isDataStoreEnabled } from '@aws-amplify/amplify-category-api';
|
|
14
|
+
import type { GenericDataSchema } from '@aws-amplify/codegen-ui';
|
|
15
|
+
import fetch, { Response } from 'node-fetch';
|
|
16
|
+
import { existsSync, writeFileSync } from 'fs';
|
|
15
17
|
|
|
16
18
|
jest.mock('@aws-amplify/amplify-cli-core', () => ({
|
|
17
19
|
...jest.requireActual('@aws-amplify/amplify-cli-core'),
|
|
@@ -23,13 +25,57 @@ jest.mock('@aws-amplify/amplify-cli-core', () => ({
|
|
|
23
25
|
jest.mock('../commands/utils/featureFlags', () => ({
|
|
24
26
|
getTransformerVersion: jest.fn().mockReturnValue(2),
|
|
25
27
|
}));
|
|
28
|
+
jest.mock('@aws-amplify/amplify-category-api', () => ({
|
|
29
|
+
...jest.requireActual('@aws-amplify/amplify-category-api'),
|
|
30
|
+
isDataStoreEnabled: jest.fn(),
|
|
31
|
+
}));
|
|
32
|
+
jest.mock('fs');
|
|
33
|
+
jest.mock('node-fetch');
|
|
26
34
|
|
|
27
35
|
const awsMock = aws as any;
|
|
28
36
|
const stateManagerMock = stateManager as any;
|
|
29
|
-
const
|
|
37
|
+
const isDataStoreEnabledMocked = jest.mocked(isDataStoreEnabled);
|
|
38
|
+
const mockWriteFileSync = jest.mocked(writeFileSync);
|
|
39
|
+
const mockExistsSync = jest.mocked(existsSync);
|
|
40
|
+
const mockNodeFetch = jest.mocked(fetch);
|
|
41
|
+
|
|
30
42
|
describe('should sync amplify ui builder components', () => {
|
|
31
43
|
let context: any;
|
|
44
|
+
const env = process.env;
|
|
45
|
+
|
|
46
|
+
const mockGenericDataSchema: GenericDataSchema = {
|
|
47
|
+
dataSourceType: 'DataStore',
|
|
48
|
+
models: {
|
|
49
|
+
Blog: {
|
|
50
|
+
fields: {
|
|
51
|
+
id: { dataType: 'ID', required: true, readOnly: false, isArray: false },
|
|
52
|
+
},
|
|
53
|
+
primaryKeys: ['id'],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
enums: {
|
|
57
|
+
Status: { values: ['ENABLED', 'DISABLED', 'HIDDEN'] },
|
|
58
|
+
},
|
|
59
|
+
nonModels: {
|
|
60
|
+
Metadata: {
|
|
61
|
+
fields: {
|
|
62
|
+
name: {
|
|
63
|
+
dataType: 'String',
|
|
64
|
+
required: false,
|
|
65
|
+
readOnly: false,
|
|
66
|
+
isArray: false,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
32
73
|
beforeEach(() => {
|
|
74
|
+
mockNodeFetch.mockReset();
|
|
75
|
+
process.env = { ...env };
|
|
76
|
+
|
|
77
|
+
isDataStoreEnabledMocked.mockResolvedValue(true);
|
|
78
|
+
mockExistsSync.mockReturnValue(false);
|
|
33
79
|
context = {
|
|
34
80
|
exeInfo: {
|
|
35
81
|
projectConfig: {
|
|
@@ -147,29 +193,10 @@ describe('should sync amplify ui builder components', () => {
|
|
|
147
193
|
})),
|
|
148
194
|
})),
|
|
149
195
|
}));
|
|
150
|
-
|
|
151
|
-
createUiBuilderComponentDependencyMock.createUiBuilderComponent = jest.fn();
|
|
152
|
-
createUiBuilderComponentDependencyMock.createUiBuilderTheme = jest.fn();
|
|
153
|
-
createUiBuilderComponentDependencyMock.createUiBuilderForm = jest.fn();
|
|
154
|
-
createUiBuilderComponentDependencyMock.createUiBuilderView = jest.fn();
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('pulls components from aws-sdk and passes them to createUiBuilderComponent', () => {
|
|
158
|
-
generateUiBuilderComponents(context, []);
|
|
159
196
|
});
|
|
160
197
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
throw new Error('ahhh!'); // eslint-disable-line spellcheck/spell-checker
|
|
164
|
-
});
|
|
165
|
-
expect(async () => generateUiBuilderComponents(context, [])).not.toThrow();
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('does not throw an error when createUiBuilderThemes fails', () => {
|
|
169
|
-
createUiBuilderComponentDependencyMock.createUiBuilderComponent = jest.fn(() => {
|
|
170
|
-
throw new Error('ahhh!'); // eslint-disable-line spellcheck/spell-checker
|
|
171
|
-
});
|
|
172
|
-
expect(async () => generateUiBuilderThemes(context, [])).not.toThrow();
|
|
198
|
+
afterEach(() => {
|
|
199
|
+
process.env = env;
|
|
173
200
|
});
|
|
174
201
|
|
|
175
202
|
it('can getAmplifyUIBuilderService', async () => {
|
|
@@ -190,110 +217,94 @@ describe('should sync amplify ui builder components', () => {
|
|
|
190
217
|
}),
|
|
191
218
|
);
|
|
192
219
|
});
|
|
220
|
+
|
|
193
221
|
it('can list components', async () => {
|
|
194
222
|
const client = await AmplifyStudioClient.setClientInfo(context);
|
|
195
223
|
const components = await client.listComponents();
|
|
196
224
|
expect(components.entities).toHaveLength(1);
|
|
197
225
|
});
|
|
226
|
+
|
|
198
227
|
it('can list themes', async () => {
|
|
199
228
|
const client = await AmplifyStudioClient.setClientInfo(context);
|
|
200
229
|
const themes = await client.listThemes();
|
|
201
230
|
expect(themes.entities).toHaveLength(1);
|
|
202
231
|
});
|
|
232
|
+
|
|
203
233
|
it('can list forms', async () => {
|
|
204
234
|
const client = await AmplifyStudioClient.setClientInfo(context);
|
|
205
235
|
const forms = await client.listForms();
|
|
206
236
|
expect(forms.entities).toHaveLength(1);
|
|
207
237
|
});
|
|
238
|
+
|
|
208
239
|
it('can getAppId', async () => {
|
|
209
240
|
const appId = getAppId(context);
|
|
210
241
|
expect(appId).toBe('testAppId');
|
|
211
242
|
});
|
|
243
|
+
|
|
212
244
|
it('can getEnvName', () => {
|
|
213
245
|
const envName = getEnvName(context);
|
|
214
246
|
expect(envName).toBe('testEnvName');
|
|
215
247
|
});
|
|
248
|
+
|
|
216
249
|
it('can resolveAppId', async () => {
|
|
217
250
|
const appId = resolveAppId();
|
|
218
251
|
expect(appId).toBe('testAppId');
|
|
219
252
|
});
|
|
253
|
+
|
|
220
254
|
it('can throw on getAppId', async () => {
|
|
221
255
|
context.input.options.appId = null;
|
|
222
256
|
context.amplify.invokePluginMethod = () => null;
|
|
223
257
|
stateManagerMock.getMeta = () => ({});
|
|
224
258
|
expect(() => getAppId(context)).toThrowError();
|
|
225
259
|
});
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
expect(components.every((component) => component.resultType === 'SUCCESS')).toBeTruthy();
|
|
230
|
-
});
|
|
231
|
-
it('can handle failed generation generate ui builder components', async () => {
|
|
232
|
-
createUiBuilderComponentDependencyMock.createUiBuilderComponent = jest.fn().mockImplementation(() => {
|
|
233
|
-
throw new Error('ahh!');
|
|
234
|
-
});
|
|
235
|
-
const components = generateUiBuilderComponents(context, [{}, {}]);
|
|
236
|
-
expect(components.every((component) => component.resultType === 'FAILURE')).toBeTruthy();
|
|
237
|
-
});
|
|
238
|
-
it('can generate ui builder themes', async () => {
|
|
239
|
-
createUiBuilderComponentDependencyMock.createUiBuilderTheme = jest.fn().mockImplementation(() => ({}));
|
|
240
|
-
const themes = generateUiBuilderThemes(context, [{}, {}]);
|
|
241
|
-
expect(themes.every((theme) => theme.resultType === 'SUCCESS')).toBeTruthy();
|
|
242
|
-
});
|
|
243
|
-
it('can handle failed generation generate ui builder themes', async () => {
|
|
244
|
-
createUiBuilderComponentDependencyMock.createUiBuilderTheme = jest.fn().mockImplementation(() => {
|
|
245
|
-
throw new Error('ahh!');
|
|
246
|
-
});
|
|
247
|
-
const themes = generateUiBuilderThemes(context, [{}, {}]);
|
|
248
|
-
expect(themes.every((theme) => theme.resultType === 'FAILURE')).toBeTruthy();
|
|
249
|
-
});
|
|
250
|
-
it('can generate ui builder default theme when no themes are passed', async () => {
|
|
251
|
-
createUiBuilderComponentDependencyMock.createUiBuilderTheme = jest.fn().mockImplementation(() => ({}));
|
|
252
|
-
const themes = generateUiBuilderThemes(context, []);
|
|
253
|
-
expect(themes.every((theme) => theme.resultType === 'SUCCESS')).toBeTruthy();
|
|
254
|
-
});
|
|
255
|
-
it('can handle failed generation generate ui builder default theme when no themes are passed', async () => {
|
|
256
|
-
createUiBuilderComponentDependencyMock.createUiBuilderTheme = jest.fn().mockImplementation(() => {
|
|
257
|
-
throw new Error('ahh!');
|
|
258
|
-
});
|
|
259
|
-
const themes = generateUiBuilderThemes(context, []);
|
|
260
|
-
expect(themes.every((theme) => theme.resultType === 'FAILURE')).toBeTruthy();
|
|
260
|
+
|
|
261
|
+
it('can map generic data schema to start codegen job request', () => {
|
|
262
|
+
expect(mapGenericDataSchemaToCodegen(mockGenericDataSchema)).toMatchSnapshot();
|
|
261
263
|
});
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
|
|
264
|
+
|
|
265
|
+
it('can wait for a succeeded job', async () => {
|
|
266
|
+
const succeededJob = { status: 'succeeded' };
|
|
267
|
+
const getJob = jest.fn().mockResolvedValueOnce({ status: 'in_progress' }).mockResolvedValueOnce(succeededJob);
|
|
268
|
+
const job = await waitForSucceededJob(getJob, { pollInterval: 1 });
|
|
269
|
+
expect(job).toEqual(succeededJob);
|
|
266
270
|
});
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
expect(forms.every((form) => form.resultType === 'FAILURE')).toBeTruthy();
|
|
271
|
+
|
|
272
|
+
it('can throw if job failed', async () => {
|
|
273
|
+
const statusMessage = 'failed status';
|
|
274
|
+
const getJob = jest.fn().mockResolvedValueOnce({ status: 'in_progress' }).mockResolvedValueOnce({ status: 'failed', statusMessage });
|
|
275
|
+
await expect(waitForSucceededJob(getJob, { pollInterval: 2 })).rejects.toThrow(statusMessage);
|
|
273
276
|
});
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
expect(
|
|
277
|
+
|
|
278
|
+
it('can throw after timeout when waiting for a succeeded job', async () => {
|
|
279
|
+
process.env.UI_BUILDER_CODEGENJOB_TIMEOUT = '1';
|
|
280
|
+
const succeededJob = { status: 'succeeded' };
|
|
281
|
+
const getJob = jest.fn().mockResolvedValueOnce({ status: 'in_progress' }).mockResolvedValueOnce(succeededJob);
|
|
282
|
+
await expect(waitForSucceededJob(getJob, { pollInterval: 2 })).rejects.toThrow('Failed to return codegen job');
|
|
280
283
|
});
|
|
281
284
|
|
|
282
|
-
it('
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
285
|
+
it('can extract ui components from archive', async () => {
|
|
286
|
+
const mockedFetchResponse = {
|
|
287
|
+
ok: true,
|
|
288
|
+
json: jest.fn().mockResolvedValue({
|
|
289
|
+
Output: [
|
|
290
|
+
{
|
|
291
|
+
downloadUrl: 'https://s3.com',
|
|
292
|
+
fileName: 'MyComponent.jsx',
|
|
293
|
+
schemaName: 'MyComponent',
|
|
294
|
+
},
|
|
295
|
+
],
|
|
296
|
+
}),
|
|
297
|
+
text: jest.fn().mockResolvedValue('source code'),
|
|
298
|
+
} as unknown as Response;
|
|
299
|
+
mockNodeFetch.mockResolvedValue(mockedFetchResponse);
|
|
300
|
+
mockExistsSync.mockReturnValue(true);
|
|
301
|
+
await extractUIComponents('https:://example.aws', 'tmp/ui-components');
|
|
302
|
+
expect(mockWriteFileSync).toHaveBeenCalledWith('tmp/ui-components/MyComponent.jsx', 'source code');
|
|
292
303
|
});
|
|
293
304
|
|
|
294
|
-
it('
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
expect(
|
|
305
|
+
it('fetchWithRetries retries 3 times', async () => {
|
|
306
|
+
mockNodeFetch.mockRejectedValue(new Error('Server dropped the connection'));
|
|
307
|
+
await expect(fetchWithRetries('https://amazon.com')).rejects.toThrowError('Fetch reached max number of retries without succeeding');
|
|
308
|
+
expect(mockNodeFetch).toHaveBeenCalledTimes(3);
|
|
298
309
|
});
|
|
299
310
|
});
|