Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v1.32.0 #837

Merged
merged 8 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,5 @@
"tsconfig-paths": "^4.2.0",
"type-fest": "4.10.3"
},
"version": "1.31.4"
"version": "1.32.0"
}
Original file line number Diff line number Diff line change
Expand Up @@ -226,4 +226,91 @@ describe('make http request', () => {
mocks.httpRequest.mockRejectedValueOnce(disallowedIpError)
await expect(makeRequestAction.run($)).rejects.toThrowError(StepError)
})

describe('tests that data is valid JSON', () => {
// NOTE: caters for existing users that are sending strings in the data field
it.each(['[1, 2, 3]', 'meep meep'])(
'should not throw error if data is string',
async (testData: any) => {
$.step.parameters.method = 'POST'
$.step.parameters.data = testData
$.step.parameters.url = 'http://test.local/endpoint?1234'

mocks.httpRequest.mockReturnValue('mock response')

await makeRequestAction.run($).catch(() => null)
expect(mocks.httpRequest).toHaveBeenCalledWith(
expect.objectContaining({
url: $.step.parameters.url,
method: $.step.parameters.method,
data: $.step.parameters.data,
}),
)
},
)

it.each([
'{"abc": 123}',
'{"abc": "def", "ghi": 456, "jkl": {"nested": "nested-value"}}',
'{"abc": "def", "ghi": 456, "jkl": {"nested": {"nested-nested": "nested-nested-value"}}}',
JSON.stringify({ data: undefined }),
JSON.stringify({ data: null }),
null,
'',
])(
'should not throw error if data is valid JSON or null or empty string',
async (testJSON: any) => {
$.step.parameters.method = 'POST'
$.step.parameters.data = testJSON

$.step.parameters.url = 'http://test.local/endpoint?1234'
mocks.httpRequest.mockReturnValue('mock response')

await makeRequestAction.run($).catch(() => null)
expect(mocks.httpRequest).toHaveBeenCalledWith(
expect.objectContaining({
url: $.step.parameters.url,
method: $.step.parameters.method,
data: $.step.parameters.data,
}),
)
},
)

it.each([
'{"abc": 123',
'"abc": 123}',
'{""abc"": "def"}',
'{"name": "zuck""}',
'{"name": "zuck", "age": "40}',
'{ this looks like json but isnt }',
])(
'should throw error if data is not valid JSON',
async (testJSON: any) => {
$.step.parameters.method = 'POST'
$.step.parameters.data = testJSON
$.step.parameters.url = 'http://test.local/endpoint?1234'

mocks.httpRequest.mockReturnValue('mock response')
await expect(makeRequestAction.run($)).rejects.toThrowError(
'Invalid JSON data',
)
},
)
})

describe('escaping variables should maintain original type', () => {
it.each([
[true, true],
[false, false],
['true', 'true'],
[123, 123],
['string with "quotes" inside', 'string with \\"quotes\\" inside'],
['string without quotes', 'string without quotes'],
['{string with braces}', '{string with braces}'],
])('should escape variables', (input, expected) => {
const escaped = makeRequestAction.preprocessVariable('data', input)
expect(escaped).toBe(expected)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,28 @@ const action: IRawAction = {
},
],

preprocessVariable(parameterKey: string, variableValue: unknown) {
if (parameterKey === 'data' && typeof variableValue === 'string') {
// NOTE: this removes the " from the start and end of the string
// as it is already added in the user input
return JSON.stringify(variableValue).slice(1, -1)
}
return variableValue
},

async run($) {
const method = $.step.parameters.method as TMethod
const data = $.step.parameters.data as string
const url = $.step.parameters.url as string

try {
const parsedS = requestSchema.parse($.step.parameters)
const { customHeaders } = parsedS
const { customHeaders, data: parsedData } = parsedS

let response = await $.http.request({
url,
method,
data,
data: parsedData,
maxRedirects: 0,
headers: customHeaders,
// overwriting this to allow redirects to resolve
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,27 @@ export const requestSchema = z.object({
return result
})
.nullish(),
data: z
.string()
.transform((str, ctx) => {
// Allow empty string
if (str === '') {
return str
}

try {
// NOTE: assume that user is trying to input JSON data if it starts with { or ends with }
if (str.startsWith('{') || str.endsWith('}')) {
JSON.parse(str) // to test for valid JSON
}
return str
} catch (e) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Invalid JSON data',
})
return z.NEVER
}
})
.nullish(),
})
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { TBeforeRequest } from '@plumber/types'

const addHeaders: TBeforeRequest = async ($, requestConfig) => {
const authData = $.auth.data
requestConfig.headers.set('Content-Type', 'application/json', false)

if (authData?.headers) {
requestConfig.headers.set('Content-Type', 'application/json', true)
Object.entries(authData.headers).forEach(([key, value]) =>
requestConfig.headers.set(key, value),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,10 @@ describe('common date-time formatter functions', () => {
expect(dateTime.toUnixInteger()).toEqual(1727452800)
},
)

it('supports parsing MyInfo Child date field', () => {
const dateTime = parseDateTime('dd/LL/yyyy', '25/03/2024')
expect(dateTime.toUnixInteger()).toEqual(1711296000)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,54 @@ describe('convert date time', () => {
toFormat: 'dd/LL/yy',
expectedResult: '01/04/24',
},
{
inputFormat: 'dd/LL/yy',
inputValue: '01/04/24',
toFormat: 'dd/LL/yyyy',
expectedResult: '01/04/2024',
},
{
inputFormat: 'dd/LL/yyyy',
inputValue: '01/04/2024',
toFormat: 'dd LLLL yyyy',
expectedResult: '01 April 2024',
},
{
inputFormat: 'dd LLLL yyyy',
inputValue: '01 April 2024',
toFormat: 'yyyy/LL/dd',
expectedResult: '2024/04/01',
},
{
inputFormat: 'yyyy/LL/dd',
inputValue: '2024/04/01',
toFormat: 'hh:mm a',
expectedResult: '12:00 am',
},
{
inputFormat: 'hh:mm a',
inputValue: '11:45 pm',
toFormat: 'hh:mm:ss a',
expectedResult: '11:45:00 pm',
},
{
inputFormat: 'hh:mm:ss a',
inputValue: '11:45:00 pm',
toFormat: 'hh:mm a',
expectedResult: '11:45 pm',
},
{
inputFormat: 'dd LLL yyyy hh:mm a',
inputValue: '01 Apr 2024 11:45 pm',
toFormat: 'dd LLL yyyy',
expectedResult: '01 Apr 2024',
},
{
inputFormat: 'dd LLL yyyy hh:mm:ss a',
inputValue: '01 Apr 2024 11:45:30 pm',
toFormat: 'hh:mm:ss a',
expectedResult: '11:45:30 pm',
},
])('can handle all supported input formats', (testParams) => {
const { inputFormat, inputValue, toFormat, expectedResult } = testParams
$.step.parameters = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { z } from 'zod'

import { ensureZodEnumValue } from '@/helpers/zod-utils'

// These are the list of common input and output date format options
export const commonDateFormats = [
'dd/LL/yy',
'dd/LL/yyyy',
'dd LLL yyyy',
'dd LLLL yyyy',
'yyyy/LL/dd',
'hh:mm a',
'hh:mm:ss a',
'dd LLL yyyy hh:mm a',
'dd LLL yyyy hh:mm:ss a',
] as const

const formatStringsEnum = z.enum(commonDateFormats)

export const commonDateFormatOptions = [
{
label: 'DD/MM/YY',
description: '25/03/24',
value: ensureZodEnumValue(formatStringsEnum, 'dd/LL/yy'),
},
{
label: 'DD/MM/YYYY',
description: '25/03/2024',
value: ensureZodEnumValue(formatStringsEnum, 'dd/LL/yyyy'),
},
{
label: 'DD MMM YYYY',
description: '25 Mar 2024',
value: ensureZodEnumValue(formatStringsEnum, 'dd LLL yyyy'),
},
{
label: 'DD MMMM YYYY',
description: '25 March 2024',
value: ensureZodEnumValue(formatStringsEnum, 'dd LLLL yyyy'),
},
{
label: 'YYYY/MM/DD',
description: '2024/03/25',
value: ensureZodEnumValue(formatStringsEnum, 'yyyy/LL/dd'),
},
{
label: 'HH:mm (am/pm)',
description: '12:04 PM',
value: ensureZodEnumValue(formatStringsEnum, 'hh:mm a'),
},
{
label: 'HH:mm:ss (am/pm)',
description: '12:04:05 pm',
value: ensureZodEnumValue(formatStringsEnum, 'hh:mm:ss a'),
},
{
label: 'DD MMM YYYY HH:mm (am/pm)',
description: '25 Mar 2024 12:04 pm',
value: ensureZodEnumValue(formatStringsEnum, 'dd LLL yyyy hh:mm a'),
},
{
label: 'DD MMM YYYY HH:mm:ss (am/pm)',
description: '25 Mar 2024 12:04:05 pm',
value: ensureZodEnumValue(formatStringsEnum, 'dd LLL yyyy hh:mm:ss a'),
},
]
Loading
Loading