Skip to content

Commit 4b73ca6

Browse files
committed
bugfix(common) Stripping proto properties works with null values
If an optional property has an allowed null value it is now considered when stripping proto props.
1 parent 1425635 commit 4b73ca6

2 files changed

Lines changed: 69 additions & 1 deletion

File tree

packages/common/pipes/validation.pipe.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export class ValidationPipe implements PipeTransform<any> {
9494
}
9595

9696
private stripProtoKeys(value: Record<string, any>) {
97+
if (isNil(value)) { return; }
9798
delete value.__proto__;
9899
const keys = Object.keys(value);
99100
keys

packages/common/test/pipes/validation.pipe.spec.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ class TestModel {
2626
@IsString() public prop1: string;
2727

2828
@IsString() public prop2: string;
29+
30+
@IsOptional()
31+
@IsString()
32+
public optionalProp: string;
2933
}
3034

3135
describe('ValidationPipe', () => {
@@ -46,13 +50,34 @@ describe('ValidationPipe', () => {
4650
beforeEach(() => {
4751
target = new ValidationPipe();
4852
});
49-
it('should return the value unchanged', async () => {
53+
it('should return the value unchanged if optional value is not defined', async () => {
5054
const testObj = { prop1: 'value1', prop2: 'value2' };
5155
expect(await target.transform(testObj, {} as any)).to.equal(testObj);
5256
expect(
5357
await target.transform(testObj, metadata as any),
5458
).to.not.be.instanceOf(TestModel);
5559
});
60+
it('should return the value unchanged if optional value is set undefined', async () => {
61+
const testObj = { prop1: 'value1', prop2: 'value2', optionalProp: undefined };
62+
expect(await target.transform(testObj, {} as any)).to.equal(testObj);
63+
expect(
64+
await target.transform(testObj, metadata as any),
65+
).to.not.be.instanceOf(TestModel);
66+
});
67+
it('should return the value unchanged if optional value is null', async () => {
68+
const testObj = { prop1: 'value1', prop2: 'value2', optionalProp: null };
69+
expect(await target.transform(testObj, {} as any)).to.equal(testObj);
70+
expect(
71+
await target.transform(testObj, metadata as any),
72+
).to.not.be.instanceOf(TestModel);
73+
});
74+
it('should return the value unchanged if optional value is set', async () => {
75+
const testObj = { prop1: 'value1', prop2: 'value2', optionalProp: 'optional value' };
76+
expect(await target.transform(testObj, {} as any)).to.equal(testObj);
77+
expect(
78+
await target.transform(testObj, metadata as any),
79+
).to.not.be.instanceOf(TestModel);
80+
});
5681
});
5782
describe('when validation fails', () => {
5883
beforeEach(() => {
@@ -134,6 +159,48 @@ describe('ValidationPipe', () => {
134159
expect(
135160
await target.transform(testObj, metadata),
136161
).to.not.have.property('prop3');
162+
expect(
163+
await target.transform(testObj, metadata),
164+
).to.not.have.property('optionalProp');
165+
});
166+
it('should return a plain object without extra properties if optional prop is defined', async () => {
167+
target = new ValidationPipe({ transform: false, whitelist: true });
168+
const testObj = { prop1: 'value1', prop2: 'value2', prop3: 'value3', optionalProp: 'optional value' };
169+
expect(
170+
await target.transform(testObj, metadata),
171+
).to.not.be.instanceOf(TestModel);
172+
expect(
173+
await target.transform(testObj, metadata),
174+
).to.not.have.property('prop3');
175+
expect(
176+
await target.transform(testObj, metadata),
177+
).to.have.property('optionalProp');
178+
});
179+
it('should return a plain object without extra properties if optional prop is undefined', async () => {
180+
target = new ValidationPipe({ transform: false, whitelist: true });
181+
const testObj = { prop1: 'value1', prop2: 'value2', prop3: 'value3', optionalProp: undefined };
182+
expect(
183+
await target.transform(testObj, metadata),
184+
).to.not.be.instanceOf(TestModel);
185+
expect(
186+
await target.transform(testObj, metadata),
187+
).to.not.have.property('prop3');
188+
expect(
189+
await target.transform(testObj, metadata),
190+
).to.have.property('optionalProp');
191+
});
192+
it('should return a plain object without extra properties if optional prop is null', async () => {
193+
target = new ValidationPipe({ transform: false, whitelist: true });
194+
const testObj = { prop1: 'value1', prop2: 'value2', prop3: 'value3', optionalProp: null };
195+
expect(
196+
await target.transform(testObj, metadata),
197+
).to.not.be.instanceOf(TestModel);
198+
expect(
199+
await target.transform(testObj, metadata),
200+
).to.not.have.property('prop3');
201+
expect(
202+
await target.transform(testObj, metadata),
203+
).to.have.property('optionalProp');
137204
});
138205
});
139206
describe('when validation rejects', () => {

0 commit comments

Comments
 (0)