codify-plugin-lib 1.0.64 → 1.0.66

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,193 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { Plugin } from './plugin.js';
3
+ import { ParameterOperation, ResourceOperation, StringIndexedObject } from 'codify-schemas';
4
+ import { Resource } from './resource.js';
5
+ import { Plan } from './plan.js';
6
+ import { ValidationResult } from './resource-types.js';
7
+ import { ApplyValidationError } from './errors.js';
8
+
9
+ interface TestConfig extends StringIndexedObject {
10
+ propA: string;
11
+ propB: number;
12
+ propC?: string;
13
+ }
14
+
15
+ class TestResource extends Resource<TestConfig> {
16
+ constructor() {
17
+ super({
18
+ type: 'testResource'
19
+ });
20
+ }
21
+
22
+ applyCreate(plan: Plan<TestConfig>): Promise<void> {
23
+ return Promise.resolve(undefined);
24
+ }
25
+
26
+ applyDestroy(plan: Plan<TestConfig>): Promise<void> {
27
+ return Promise.resolve(undefined);
28
+ }
29
+
30
+ async refresh(keys: Map<string, unknown>): Promise<Partial<TestConfig> | null> {
31
+ return {
32
+ propA: 'a',
33
+ propB: 10,
34
+ propC: 'c',
35
+ };
36
+ }
37
+
38
+ async validateResource(config: unknown): Promise<ValidationResult> {
39
+ return {
40
+ isValid: true
41
+ }
42
+ }
43
+ }
44
+
45
+ describe('Plugin tests', () => {
46
+ it('Validates that applies were successfully applied', async () => {
47
+ const resource= new class extends TestResource {
48
+ async applyCreate(plan: Plan<TestConfig>): Promise<void> {
49
+ }
50
+
51
+ // Refresh has to line up with desired for the apply to go through
52
+ async refresh(keys: Map<string, unknown>): Promise<Partial<TestConfig> | null> {
53
+ return {
54
+ propA: 'abc'
55
+ }
56
+ }
57
+ }
58
+
59
+ const plugin = Plugin.create('testPlugin', [resource])
60
+
61
+ const plan = {
62
+ operation: ResourceOperation.CREATE,
63
+ resourceType: 'testResource',
64
+ parameters: [
65
+ { name: 'propA', operation: ParameterOperation.ADD, newValue: 'abc', previousValue: null },
66
+ ]
67
+ };
68
+
69
+ // If this doesn't throw then it passes the test
70
+ await plugin.apply({ plan });
71
+ });
72
+
73
+ it('Validates that applies were successfully applied (error)', async () => {
74
+ const resource = new class extends TestResource {
75
+ async applyCreate(plan: Plan<TestConfig>): Promise<void> {
76
+ }
77
+
78
+ // Return null to indicate that the resource was not created
79
+ async refresh(keys: Map<string, unknown>): Promise<Partial<TestConfig> | null> {
80
+ return null;
81
+ }
82
+ }
83
+ const plugin = Plugin.create('testPlugin', [resource])
84
+
85
+ const plan = {
86
+ operation: ResourceOperation.CREATE,
87
+ resourceType: 'testResource',
88
+ parameters: [
89
+ { name: 'propA', operation: ParameterOperation.ADD, newValue: 'abc', previousValue: null },
90
+ ]
91
+ };
92
+
93
+ await expect(async () => plugin.apply({ plan })).rejects.toThrowError(expect.any(ApplyValidationError));
94
+ });
95
+
96
+ it('Validates that deletes were successfully applied', async () => {
97
+ const resource = new class extends TestResource {
98
+ async applyCreate(plan: Plan<TestConfig>): Promise<void> {
99
+ }
100
+
101
+ // Return null to indicate that the resource was deleted
102
+ async refresh(keys: Map<string, unknown>): Promise<Partial<TestConfig> | null> {
103
+ return null;
104
+ }
105
+ }
106
+
107
+ const testPlugin = Plugin.create('testPlugin', [resource])
108
+
109
+ const plan = {
110
+ operation: ResourceOperation.DESTROY,
111
+ resourceType: 'testResource',
112
+ parameters: [
113
+ { name: 'propA', operation: ParameterOperation.REMOVE, newValue: null, previousValue: 'abc' },
114
+ ]
115
+ };
116
+
117
+ // If this doesn't throw then it passes the test
118
+ await testPlugin.apply({ plan })
119
+ });
120
+
121
+ it('Validates that deletes were successfully applied (error)', async () => {
122
+ const resource = new class extends TestResource {
123
+ async applyCreate(plan: Plan<TestConfig>): Promise<void> {
124
+ }
125
+
126
+ // Return a value to indicate that the resource still exists
127
+ async refresh(keys: Map<string, unknown>): Promise<Partial<TestConfig> | null> {
128
+ return { propA: 'abc' };
129
+ }
130
+ }
131
+
132
+ const testPlugin = Plugin.create('testPlugin', [resource])
133
+
134
+ const plan = {
135
+ operation: ResourceOperation.DESTROY,
136
+ resourceType: 'testResource',
137
+ parameters: [
138
+ { name: 'propA', operation: ParameterOperation.REMOVE, newValue: null, previousValue: 'abc' },
139
+ ]
140
+ };
141
+
142
+ // If this doesn't throw then it passes the test
143
+ expect(async () => await testPlugin.apply({ plan })).rejects.toThrowError(expect.any(ApplyValidationError));
144
+ });
145
+
146
+ it('Validates that re-create was successfully applied', async () => {
147
+ const resource = new class extends TestResource {
148
+ async applyCreate(plan: Plan<TestConfig>): Promise<void> {
149
+ }
150
+
151
+ async refresh(keys: Map<string, unknown>): Promise<Partial<TestConfig> | null> {
152
+ return { propA: 'def'};
153
+ }
154
+ }
155
+
156
+ const testPlugin = Plugin.create('testPlugin', [resource])
157
+
158
+ const plan = {
159
+ operation: ResourceOperation.RECREATE,
160
+ resourceType: 'testResource',
161
+ parameters: [
162
+ { name: 'propA', operation: ParameterOperation.MODIFY, newValue: 'def', previousValue: 'abc' },
163
+ ]
164
+ };
165
+
166
+ // If this doesn't throw then it passes the test
167
+ await testPlugin.apply({ plan })
168
+ });
169
+
170
+ it('Validates that modify was successfully applied (error)', async () => {
171
+ const resource = new class extends TestResource {
172
+ async applyCreate(plan: Plan<TestConfig>): Promise<void> {
173
+ }
174
+
175
+ async refresh(keys: Map<string, unknown>): Promise<Partial<TestConfig> | null> {
176
+ return { propA: 'abc' };
177
+ }
178
+ }
179
+
180
+ const testPlugin = Plugin.create('testPlugin', [resource])
181
+
182
+ const plan = {
183
+ operation: ResourceOperation.DESTROY,
184
+ resourceType: 'testResource',
185
+ parameters: [
186
+ { name: 'propA', operation: ParameterOperation.REMOVE, newValue: 'def', previousValue: 'abc' },
187
+ ]
188
+ };
189
+
190
+ // If this doesn't throw then it passes the test
191
+ expect(async () => await testPlugin.apply({ plan })).rejects.toThrowError(expect.any(ApplyValidationError));
192
+ });
193
+ });
@@ -5,14 +5,24 @@ import {
5
5
  PlanRequestData,
6
6
  PlanResponseData,
7
7
  ResourceConfig,
8
+ ResourceOperation,
8
9
  ValidateRequestData,
9
10
  ValidateResponseData
10
11
  } from 'codify-schemas';
11
12
  import { Plan } from './plan.js';
12
13
  import { splitUserConfig } from '../utils/utils.js';
14
+ import { ApplyValidationError } from './errors.js';
13
15
 
14
16
  export class Plugin {
15
- planStorage: Map<string, Plan<ResourceConfig>>;
17
+ planStorage: Map<string, Plan<any>>;
18
+
19
+ static create(name: string, resources: Resource<any>[]) {
20
+ const resourceMap = new Map<string, Resource<any>>(
21
+ resources.map((r) => [r.typeId, r] as const)
22
+ );
23
+
24
+ return new Plugin(name, resourceMap);
25
+ }
16
26
 
17
27
  constructor(
18
28
  public name: string,
@@ -82,6 +92,17 @@ export class Plugin {
82
92
  }
83
93
 
84
94
  await resource.apply(plan);
95
+
96
+ // Perform a validation check after to ensure that the plan was properly applied.
97
+ // Sometimes no errors are returned (exit code 0) but the apply was not successful
98
+ const validationPlan = await resource.plan(
99
+ plan.desiredConfig,
100
+ plan.currentConfig,
101
+ true,
102
+ );
103
+ if (validationPlan.changeSet.operation !== ResourceOperation.NOOP) {
104
+ throw new ApplyValidationError(plan, validationPlan);
105
+ }
85
106
  }
86
107
 
87
108
  private resolvePlan(data: ApplyRequestData): Plan<ResourceConfig> {
@@ -6,7 +6,7 @@ import { ParameterOperation, ResourceOperation } from 'codify-schemas';
6
6
  import { TestConfig, TestResource } from './resource.test.js';
7
7
  import { TransformParameter } from './transform-parameter.js';
8
8
 
9
- class TestParameter extends StatefulParameter<TestConfig, string> {
9
+ export class TestParameter extends StatefulParameter<TestConfig, string> {
10
10
  constructor(options?: StatefulParameterOptions<string>) {
11
11
  super(options ?? {})
12
12
  }
@@ -55,11 +55,7 @@ describe('Resource parameter tests', () => {
55
55
  })
56
56
 
57
57
  expect(statefulParameter.refresh.notCalled).to.be.true;
58
- expect(plan.currentConfig).toMatchObject({
59
- type: 'resource',
60
- propA: null,
61
- propB: null,
62
- })
58
+ expect(plan.currentConfig).to.be.null;
63
59
  expect(plan.desiredConfig).toMatchObject({
64
60
  type: 'resource',
65
61
  propA: 'a',
@@ -119,7 +115,7 @@ describe('Resource parameter tests', () => {
119
115
  type: 'resource',
120
116
  parameterOptions: {
121
117
  propA: { statefulParameter: statefulParameterSpy },
122
- propB: { canModify: true },
118
+ propB: { modifyOnChange: true },
123
119
  }
124
120
  });
125
121
  }
@@ -171,10 +167,7 @@ describe('Resource parameter tests', () => {
171
167
  })
172
168
 
173
169
  expect(statefulParameter.refresh.notCalled).to.be.true;
174
- expect(plan.currentConfig).toMatchObject({
175
- type: 'resource',
176
- propA: null,
177
- })
170
+ expect(plan.currentConfig).to.be.null;
178
171
  expect(plan.desiredConfig).toMatchObject({
179
172
  type: 'resource',
180
173
  propA: 'abc',
@@ -182,7 +175,6 @@ describe('Resource parameter tests', () => {
182
175
  expect(plan.changeSet.operation).to.eq(ResourceOperation.CREATE);
183
176
  })
184
177
 
185
-
186
178
  it('Filters array results in stateless mode to prevent modify from being called', async () => {
187
179
  const statefulParameter = new class extends TestParameter {
188
180
  async refresh(): Promise<any | null> {
@@ -350,10 +342,10 @@ describe('Resource parameter tests', () => {
350
342
  propE: 'propE',
351
343
  });
352
344
 
353
- expect(plan.currentConfig.propB).to.be.lessThan(plan.currentConfig.propC as any);
354
- expect(plan.currentConfig.propC).to.be.lessThan(plan.currentConfig.propA as any);
355
- expect(plan.currentConfig.propA).to.be.lessThan(plan.currentConfig.propD as any);
356
- expect(plan.currentConfig.propD).to.be.lessThan(plan.currentConfig.propE as any);
345
+ expect(plan.currentConfig?.propB).to.be.lessThan(plan.currentConfig?.propC as any);
346
+ expect(plan.currentConfig?.propC).to.be.lessThan(plan.currentConfig?.propA as any);
347
+ expect(plan.currentConfig?.propA).to.be.lessThan(plan.currentConfig?.propD as any);
348
+ expect(plan.currentConfig?.propD).to.be.lessThan(plan.currentConfig?.propE as any);
357
349
  })
358
350
 
359
351
  it('Applies stateful parameters in the order specified', async () => {
@@ -483,9 +475,9 @@ describe('Resource parameter tests', () => {
483
475
  expect(resource.refresh.getCall(0).firstArg.has('propB')).to.be.true;
484
476
  expect(resource.refresh.getCall(0).firstArg.has('propC')).to.be.false;
485
477
 
486
- expect(plan.desiredConfig.propA).to.eq('propA');
487
- expect(plan.desiredConfig.propB).to.eq(10);
488
- expect(plan.desiredConfig.propC).to.be.undefined;
478
+ expect(plan.desiredConfig?.propA).to.eq('propA');
479
+ expect(plan.desiredConfig?.propB).to.eq(10);
480
+ expect(plan.desiredConfig?.propC).to.be.undefined;
489
481
 
490
482
  expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
491
483
  })
@@ -570,8 +562,8 @@ describe('Resource parameter tests', () => {
570
562
  propC: 'propC',
571
563
  });
572
564
 
573
- expect(plan.desiredConfig.propE).to.be.lessThan(plan.desiredConfig.propF as any);
574
- expect(plan.desiredConfig.propF).to.be.lessThan(plan.desiredConfig.propD as any);
565
+ expect(plan.desiredConfig?.propE).to.be.lessThan(plan.desiredConfig?.propF as any);
566
+ expect(plan.desiredConfig?.propF).to.be.lessThan(plan.desiredConfig?.propD as any);
575
567
  })
576
568
 
577
569
  it('Plans transform even for creating new resources', async () => {
@@ -602,11 +594,7 @@ describe('Resource parameter tests', () => {
602
594
  propB: 10,
603
595
  propC: 'propC',
604
596
  });
605
- expect(plan.currentConfig).toMatchObject({
606
- type: 'resourceType',
607
- propD: null,
608
- propE: null,
609
- })
597
+ expect(plan.currentConfig).to.be.null;
610
598
  expect(plan.desiredConfig).toMatchObject({
611
599
  type: 'resourceType',
612
600
  propD: 'abc',
@@ -0,0 +1,247 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { TestConfig, TestResource } from './resource.test.js';
3
+ import { ParameterOperation, ResourceOperation } from 'codify-schemas';
4
+ import { TestParameter } from './resource-parameters.test.js';
5
+ import { StatefulParameter } from './stateful-parameter.js';
6
+
7
+
8
+ describe('Resource tests for stateful plans', () => {
9
+ it('Supports delete operations ', async () => {
10
+ const resource = new class extends TestResource {
11
+ constructor() {
12
+ super({ type: 'resource' });
13
+ }
14
+
15
+ async refresh(keys: Map<string, unknown>): Promise<Partial<TestConfig> | null> {
16
+ return {
17
+ propA: 'propADifferent',
18
+ propB: undefined,
19
+ propC: 'propCDifferent',
20
+ }
21
+ }
22
+ }
23
+
24
+ const plan = await resource.plan(
25
+ null,
26
+ {
27
+ type: 'resource',
28
+ propA: 'propA',
29
+ propB: 10,
30
+ propC: 'propC',
31
+ }, true
32
+ );
33
+
34
+ expect(plan).toMatchObject({
35
+ changeSet: {
36
+ operation: ResourceOperation.DESTROY,
37
+ parameterChanges: [
38
+ {
39
+ name: "propA",
40
+ previousValue: "propADifferent",
41
+ newValue: null,
42
+ operation: ParameterOperation.REMOVE
43
+ },
44
+ {
45
+ name: "propC",
46
+ previousValue: "propCDifferent",
47
+ newValue: null,
48
+ operation: ParameterOperation.REMOVE
49
+ },
50
+ ]
51
+ },
52
+ resourceMetadata: {
53
+ type: 'resource'
54
+ }
55
+ })
56
+ })
57
+
58
+ it('Supports create operations', async () => {
59
+ const resource = new class extends TestResource {
60
+ constructor() {
61
+ super({ type: 'resource' });
62
+ }
63
+
64
+ async refresh(keys: Map<string, unknown>): Promise<Partial<TestConfig> | null> {
65
+ return null;
66
+ }
67
+ }
68
+
69
+ const plan = await resource.plan(
70
+ {
71
+ type: 'resource',
72
+ propA: 'propA',
73
+ propB: 10,
74
+ propC: 'propC',
75
+ },
76
+ null,
77
+ true
78
+ );
79
+
80
+ expect(plan).toMatchObject({
81
+ changeSet: {
82
+ operation: ResourceOperation.CREATE,
83
+ parameterChanges: [
84
+ {
85
+ name: "propA",
86
+ newValue: "propA",
87
+ previousValue: null,
88
+ operation: ParameterOperation.ADD
89
+ },
90
+ {
91
+ name: "propB",
92
+ newValue: 10,
93
+ previousValue: null,
94
+ operation: ParameterOperation.ADD
95
+ },
96
+ {
97
+ name: "propC",
98
+ newValue: 'propC',
99
+ previousValue: null,
100
+ operation: ParameterOperation.ADD
101
+ },
102
+ ]
103
+ },
104
+ resourceMetadata: {
105
+ type: 'resource'
106
+ }
107
+ })
108
+ })
109
+
110
+ it('Supports re-create operations', async () => {
111
+ const resource = new class extends TestResource {
112
+ constructor() {
113
+ super({ type: 'resource' });
114
+ }
115
+
116
+ async refresh(keys: Map<string, unknown>): Promise<Partial<TestConfig> | null> {
117
+ return {
118
+ propA: 'propA',
119
+ propC: 'propC',
120
+ propB: undefined
121
+ };
122
+ }
123
+ }
124
+
125
+ const plan = await resource.plan(
126
+ {
127
+ type: 'resource',
128
+ propA: 'propA',
129
+ propB: 10,
130
+ propC: 'propC',
131
+ },
132
+ {
133
+ type: 'resource',
134
+ propA: 'propA',
135
+ propC: 'propC'
136
+ },
137
+ true
138
+ );
139
+
140
+ expect(plan).toMatchObject({
141
+ changeSet: {
142
+ operation: ResourceOperation.RECREATE,
143
+ parameterChanges: expect.arrayContaining([
144
+ {
145
+ name: "propA",
146
+ newValue: "propA",
147
+ previousValue: "propA",
148
+ operation: ParameterOperation.NOOP
149
+ },
150
+ {
151
+ name: "propB",
152
+ newValue: 10,
153
+ previousValue: null,
154
+ operation: ParameterOperation.ADD
155
+ },
156
+ {
157
+ name: "propC",
158
+ newValue: 'propC',
159
+ previousValue: 'propC',
160
+ operation: ParameterOperation.NOOP
161
+ },
162
+ ])
163
+ },
164
+ resourceMetadata: {
165
+ type: 'resource'
166
+ }
167
+ })
168
+ })
169
+
170
+ it('Supports stateful parameters', async () => {
171
+ const statefulParameter = new class extends TestParameter {
172
+ async refresh(): Promise<string | null> {
173
+ return null;
174
+ }
175
+ }
176
+
177
+ const resource = new class extends TestResource {
178
+ constructor() {
179
+ super({
180
+ type: 'resource',
181
+ parameterOptions: {
182
+ propD: { statefulParameter: statefulParameter as StatefulParameter<TestConfig, string> },
183
+ }
184
+ });
185
+ }
186
+
187
+ async refresh(keys: Map<string, unknown>): Promise<Partial<TestConfig> | null> {
188
+ return {
189
+ propA: 'propA',
190
+ propC: 'propC',
191
+ propB: undefined
192
+ };
193
+ }
194
+ }
195
+
196
+ const plan = await resource.plan(
197
+ {
198
+ type: 'resource',
199
+ propA: 'propA',
200
+ propB: 10,
201
+ propC: 'propC',
202
+ propD: 'propD'
203
+ },
204
+ {
205
+ type: 'resource',
206
+ propA: 'propA',
207
+ propC: 'propC'
208
+ },
209
+ true
210
+ );
211
+
212
+ expect(plan).toMatchObject({
213
+ changeSet: {
214
+ operation: ResourceOperation.RECREATE,
215
+ parameterChanges: expect.arrayContaining([
216
+ {
217
+ name: "propA",
218
+ newValue: "propA",
219
+ previousValue: "propA",
220
+ operation: ParameterOperation.NOOP
221
+ },
222
+ {
223
+ name: "propB",
224
+ newValue: 10,
225
+ previousValue: null,
226
+ operation: ParameterOperation.ADD
227
+ },
228
+ {
229
+ name: "propC",
230
+ newValue: 'propC',
231
+ previousValue: 'propC',
232
+ operation: ParameterOperation.NOOP
233
+ },
234
+ {
235
+ name: "propD",
236
+ newValue: 'propD',
237
+ previousValue: null,
238
+ operation: ParameterOperation.ADD
239
+ },
240
+ ])
241
+ },
242
+ resourceMetadata: {
243
+ type: 'resource'
244
+ }
245
+ })
246
+ })
247
+ })
@@ -7,7 +7,7 @@ export interface ResourceParameterOptions {
7
7
  /**
8
8
  * Chose if the resource should be re-created or modified if this parameter is changed. Defaults to false (re-create).
9
9
  */
10
- canModify?: boolean;
10
+ modifyOnChange?: boolean;
11
11
  /**
12
12
  * Customize the equality comparison for a parameter.
13
13
  * @param desired
@@ -195,8 +195,8 @@ describe('Resource tests', () => {
195
195
  super({
196
196
  type: 'resource',
197
197
  parameterOptions: {
198
- propA: { canModify: true },
199
- propB: { canModify: true },
198
+ propA: { modifyOnChange: true },
199
+ propB: { modifyOnChange: true },
200
200
  }
201
201
  });
202
202
  }
@@ -218,12 +218,6 @@ describe('Resource tests', () => {
218
218
 
219
219
  it('Validates the resource options correct (pass)', () => {
220
220
  const statefulParameter = new class extends StatefulParameter<TestConfig, string> {
221
- constructor() {
222
- super({
223
- name: 'propC',
224
- });
225
- }
226
-
227
221
  async refresh(): Promise<string | null> {
228
222
  return null;
229
223
  }
@@ -244,7 +238,7 @@ describe('Resource tests', () => {
244
238
  type: 'type',
245
239
  dependencies: ['homebrew', 'python'],
246
240
  parameterOptions: {
247
- propA: { canModify: true },
241
+ propA: { modifyOnChange: true },
248
242
  propB: { statefulParameter },
249
243
  propC: { isEqual: (a, b) => true },
250
244
  }
@@ -255,12 +249,6 @@ describe('Resource tests', () => {
255
249
 
256
250
  it('Validates the resource options correct (fail)', () => {
257
251
  const statefulParameter = new class extends StatefulParameter<TestConfig, string> {
258
- constructor() {
259
- super({
260
- name: 'propC',
261
- });
262
- }
263
-
264
252
  async refresh(): Promise<string | null> {
265
253
  return null;
266
254
  }
@@ -281,7 +269,7 @@ describe('Resource tests', () => {
281
269
  type: 'type',
282
270
  dependencies: ['homebrew', 'python'],
283
271
  parameterOptions: {
284
- propA: { canModify: true },
272
+ propA: { modifyOnChange: true },
285
273
  propB: { statefulParameter },
286
274
  propC: { isEqual: (a, b) => true },
287
275
  }
@@ -313,8 +301,8 @@ describe('Resource tests', () => {
313
301
  }
314
302
 
315
303
  const plan = await resource.plan({ type: 'resource'})
316
- expect(plan.currentConfig.propA).to.eq('propAAfter');
317
- expect(plan.desiredConfig.propA).to.eq('propADefault');
304
+ expect(plan.currentConfig?.propA).to.eq('propAAfter');
305
+ expect(plan.desiredConfig?.propA).to.eq('propADefault');
318
306
  expect(plan.changeSet.operation).to.eq(ResourceOperation.RECREATE);
319
307
  })
320
308
 
@@ -339,8 +327,8 @@ describe('Resource tests', () => {
339
327
  }
340
328
 
341
329
  const plan = await resource.plan({ type: 'resource'})
342
- expect(plan.currentConfig.propE).to.eq('propEDefault');
343
- expect(plan.desiredConfig.propE).to.eq('propEDefault');
330
+ expect(plan.currentConfig?.propE).to.eq('propEDefault');
331
+ expect(plan.desiredConfig?.propE).to.eq('propEDefault');
344
332
  expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
345
333
  })
346
334
 
@@ -361,8 +349,8 @@ describe('Resource tests', () => {
361
349
  }
362
350
 
363
351
  const plan = await resource.plan({ type: 'resource'})
364
- expect(plan.currentConfig.propE).to.eq(null);
365
- expect(plan.desiredConfig.propE).to.eq('propEDefault');
352
+ expect(plan.currentConfig).to.be.null
353
+ expect(plan.desiredConfig!.propE).to.eq('propEDefault');
366
354
  expect(plan.changeSet.operation).to.eq(ResourceOperation.CREATE);
367
355
  })
368
356
 
@@ -389,8 +377,8 @@ describe('Resource tests', () => {
389
377
  }
390
378
 
391
379
  const plan = await resource.plan({ type: 'resource', propA: 'propA'})
392
- expect(plan.currentConfig.propA).to.eq('propAAfter');
393
- expect(plan.desiredConfig.propA).to.eq('propA');
380
+ expect(plan.currentConfig?.propA).to.eq('propAAfter');
381
+ expect(plan.desiredConfig?.propA).to.eq('propA');
394
382
  expect(plan.changeSet.operation).to.eq(ResourceOperation.RECREATE);
395
383
  });
396
384