Skip to content

Commit

Permalink
chore: add payments by product backend validation (#7077)
Browse files Browse the repository at this point in the history
* chore: scaffold controller code

* chore: split into services

* chore: update typeguard to check for _id and name

* chore: validate product price

* chore: update error message for payment definition failure

* chore: add unit tests for isPaymentsProducts

* chore: add tests for payments service

* chore: remove stray comment

* chore: check entire product definition

* chore: convert mongoose doc to obj for comparison

* chore: refine testcases

---------

Co-authored-by: Ken <ken@open.gov.sg>
  • Loading branch information
tshuli and KenLSM committed Feb 14, 2024
1 parent 1739804 commit 1a19628
Show file tree
Hide file tree
Showing 8 changed files with 675 additions and 4 deletions.
126 changes: 126 additions & 0 deletions shared/types/form/__tests__/product.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { ObjectId } from 'bson'
import { isPaymentsProducts } from '../product'
import { Product } from '../product'

describe('Product validation', () => {
it('should return false if products is not an array', () => {
// Arrange
const mockProductNonArray = 'some thing'

// Assert
expect(isPaymentsProducts(mockProductNonArray)).toBe(false)
})

it('should return true if products is an empty array', () => {
// Arrange
const mockProductEmptyArray: Product[] = []

// Assert
expect(isPaymentsProducts(mockProductEmptyArray)).toBe(false)
})

it('should return false if product has invalid object id', () => {
// Arrange
const mockProductInvalidId: any = [
{
name: 'some name',
description: 'some description',
multi_qty: true,
min_qty: 1,
max_qty: 1,
amount_cents: 1,
_id: 'some id',
},
]

// Assert
expect(isPaymentsProducts(mockProductInvalidId)).toBe(false)
})

it('should return false if product has no name', () => {
// Arrange
const mockProductWrongName = [
{
description: 'some description',
multi_qty: true,
min_qty: 1,
max_qty: 1,
amount_cents: 1,
_id: new ObjectId(),
},
] as unknown as Product[]

// Assert
expect(isPaymentsProducts(mockProductWrongName)).toBe(false)
})

it('should return false if there are multiple products and at least one has no name', () => {
// Arrange
const mockMultipleProductOneNoName = [
{
description: 'some description',
multi_qty: true,
min_qty: 1,
max_qty: 1,
amount_cents: 1,
_id: new ObjectId(),
},
{
name: 'has name',
multi_qty: true,
min_qty: 1,
max_qty: 1,
amount_cents: 1,
_id: new ObjectId(),
},
] as unknown as Product[]

// Assert
expect(isPaymentsProducts(mockMultipleProductOneNoName)).toBe(false)
})

it('should return true if product has valid object id and name', () => {
// Arrange
const mockProductsCorrectShape = [
{
name: 'some name',
description: 'some description',
multi_qty: true,
min_qty: 1,
max_qty: 1,
amount_cents: 1,
_id: new ObjectId(),
},
] as unknown as Product[]

// Assert
expect(isPaymentsProducts(mockProductsCorrectShape)).toBe(true)
})

it('should return true if multiple products have valid object id and name', () => {
// Arrange
const mockProductsCorrectShapeMultiple = [
{
name: 'some name',
description: 'some description',
multi_qty: true,
min_qty: 1,
max_qty: 1,
amount_cents: 1,
_id: new ObjectId(),
},
{
name: 'another name',
description: 'another description',
multi_qty: true,
min_qty: 1,
max_qty: 1,
amount_cents: 1,
_id: new ObjectId(),
},
] as unknown as Product[]

// Assert
expect(isPaymentsProducts(mockProductsCorrectShapeMultiple)).toBe(true)
})
})
20 changes: 20 additions & 0 deletions shared/types/form/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,23 @@ export type ProductItem = {
selected: boolean
quantity: number
}

// Typeguard for Product
export const isPaymentsProducts = (
products: unknown,
): products is Product[] => {
if (!Array.isArray(products)) {
return false
}
return (
products.length > 0 &&
products.every((product) => {
return (
product._id &&
String(product._id).match(/^[0-9a-fA-F]{24}$/) &&
product.name &&
typeof product.name === 'string'
)
})
)
}
Loading

0 comments on commit 1a19628

Please sign in to comment.