-
Notifications
You must be signed in to change notification settings - Fork 301
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
feat(storage-browser): validate schema of data received from read APIs #6213
base: main
Are you sure you want to change the base?
Conversation
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor feedback around aligning to existing idioms. Somewhat concerned in regards to how the UI will handle exceptions thrown from the new util and what messaging is exposed to end users
|
||
describe('checkRequiredKeys', () => { | ||
it('should not throw when all required keys are present', () => { | ||
const object: TestObject = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer declarative naming of variables implying their use case (e.g. input
)
key1?: string | null; | ||
key2?: string | null; | ||
key3?: string | null; | ||
extraKey?: string | null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the values provided are of type number
?
@@ -127,4 +128,37 @@ describe('listLocationsHandler', () => { | |||
'Storage Browser: Must provide accountId to `listCallerAccessGrants`.' | |||
); | |||
}); | |||
|
|||
it('should throw if list does not provide locations', async () => { | |||
input.config.accountId = accountId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See that mutating the test input is an existing pattern but these new tests need to create a new input for each call to avoid non-deterministic behavior between individual tests, example:
await expect(listLocationsHandler({ ...input, config: { ...input.config, accountId }})).rejects.toThrow(
'Required keys missing for ListLocationsOutput: locations.'
);
@@ -54,7 +55,9 @@ export const downloadHandler: DownloadHandler = ({ | |||
expectedBucketOwner: accountId, | |||
}, | |||
}) | |||
.then(({ url }) => { | |||
.then((result) => { | |||
checkRequiredKeys(result, 'StorageGetUrlOutput', ['url']); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the UI handle the error thrown here gracefully?
throw Error( | ||
`Required keys missing for ${objectName}: ${[...missingValues].join( | ||
', ' | ||
)}.\nObject: ${JSON.stringify(objectToCheck)}` | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is this intended to be surfaced to an end user and what actions are they expected to take in a missing key scenario?
@@ -150,6 +151,33 @@ describe('listLocationItemsHandler', () => { | |||
}) | |||
); | |||
}); | |||
|
|||
it('should throw if list does not provide items', async () => { | |||
mockList.mockResolvedValueOnce({} as any); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer @ts-expect-error
with a concise comment explaining the need for the invalid response
); | ||
}); | ||
|
||
['path', 'lastModified', 'size'].forEach((requiredKey) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer jest.each
}); | ||
|
||
await expect(listLocationItemsHandler(baseInput)).rejects.toThrow( | ||
`Required keys missing for ListOutputItem #1: ${requiredKey}.` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a single key is missing why pluralize?
objectToCheck: T, | ||
objectName: string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please updates these names to align with function parameter naming within the code base, for example:
- objectToCheck: T,
+ input: T,
- objectName: string,
+ displayName: string,
@@ -70,4 +71,15 @@ describe('downloadHandler', () => { | |||
message: errorMessage, | |||
}); | |||
}); | |||
|
|||
it('should fail if getUrl does not return a url', async () => { | |||
mockGetUrl.mockResolvedValue({} as any); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer @ts-expect-error
with a concise comment explaining the need for the invalid response
Description of changes
checkRequiredKeys
is intentionally forwards-compatible so these checks do not have to be updated every time amplify-js adds properties to the response that storage browser doesn't use.Issue #, if available
Description of how you validated changes
Checklist
yarn test
passes and tests are updated/addeddocs
,e2e
,examples
, or other private packages.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.