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

Improve types for mocking #3082

Merged
merged 7 commits into from
Oct 7, 2024
Merged

Improve types for mocking #3082

merged 7 commits into from
Oct 7, 2024

Conversation

oleg-codaio
Copy link
Contributor

@oleg-codaio oleg-codaio commented Oct 3, 2024

This PR is part of a stack created with Aviator.

Improving stubs in MockExecutionContext to be strongly typed.

Also adding a transformSyncFormulaResultToGetPermissionsRequest helper for writing tests working with permissions.

PTAL @coda/packs

@oleg-codaio oleg-codaio requested a review from a team as a code owner October 3, 2024 02:30
@@ -30,7 +40,9 @@ export function newMockExecutionContext(overrides?: Partial<MockExecutionContext
timezone: 'America/Los_Angeles',
invocationToken: v4(),
fetcher: {
fetch: sinon.stub(),
fetch: sinon.stub<[FetchRequest], Promise<FetchResponse>>().callsFake(async r => {
throw new Error(`Unhandled fetch: ${r.method} ${r.url}`);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating newMockExecutionContext to throw by default (rather than just return an empty value).

Copy link
Collaborator

@jonathan-codaio jonathan-codaio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CHANGELOG.md Outdated
@@ -4,6 +4,10 @@ This changelog keeps track of all changes to the Packs SDK. We follow convention

## [Unreleased]

### Changed

- Improve types for testing
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The returns --> resolves thing seems like the most significant change, would call that out. Will external developers who have written unittests also need to update all usage like you did in the packs repo? If so I think we need to pre-announce this and explain how to update things. Clearly what was there before was broken so it's a good change but if it's not backwards-compatible we need to give a heads-up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, if external developers wrote unit tests that didn't correctly return a promise (but instead returned a value), they'd need to update their tests to also use resolves to pass type checks. Functionally these tests still work because our code must in general use await rather than attempting to do promise chains with .then() - the latter would have caused RTEs otherwise.

@ekoleda-codaio can you help with the necessary announcement for this change?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ekoleda-codaio I think the only developer-facing change to announce would be that if somebody previously wrote tests with newMockExecutionContext() and they used context.fetcher.fetch.returns(...) they need to update it to use context.fetcher.fetch.resolves(...). This should always have been the case but the old behavior was inaccurate considering these are async methods.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying, I missed this callout. Since tests could only be written with the CLI, and SDK version upgrades are manual and optional for the CLI (compared to the Pack Studio), I think it's fine to release this without an announcement or warning. I also suspect that the number of developers writing tests period is very small, so I expect the blast radius here to be incredibly small. A clear note in the Changelog is likely sufficient, but I can also write up a short community post once the version goes live.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok that's fine, let's just go with a more thorough changelog entry.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, updated the changelog.

*
* @hidden
*/
export function transformSyncFormulaResultToGetPermissionsRequest(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah this is unfortunate. This is because when you call a sync formula in a test you get back normalized values?

Originally when we created the unittest framework, you got back pre-normalized values, which to me made the most sense because the pack maker is not supposed to care about normalization, it's a thing Coda does on their behalf but they don't really need to know or care about. At some point we made the unittest framework more robust or moved where normalization happens and as a side effect the return values started coming back normalized. So now developers do need to confront this detail.

It's probably worth seeing briefly whether there's a way to get back pre-normalized values during testing so that developers can just ignore this entirely. It might not be feasible though if things are tightly wound up in there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, correct - when you call executeSyncFormulaFromPackDef or executeSyncFormulaFromPackDefSingleIteration that returns the normalized values. (There are some examples in the packs repo.) This happens in testing/execution.ts in findAndExecutePackFunction().

If we want to test permissions with the same values as passed in during ingestions then we need to untransform the result. However it looks like @alexd-codaio had a todo to revert these transforms:

// TODO(alexd): Switch this to false or remove when we launch 1.0.0
useDeprecatedResultNormalization = true,

However if we bypass transforms then extraneous properties aren't filtered out, and we also have to set validateResult: false since that seems broken too. So there's a bit of work, we might want to transform and untransform back implicitly (perhaps add a new flag).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh good find. Ignoring extraneous properties for a second, could you get by without transformSyncFormulaResultToGetPermissionsRequest() if you just used useDeprecatedResultNormalization = false?

That said, transforming and untransforming I think does simulate what happens in coda, so it seems reasonable to do that and not expose an untransformer. I'd rather we just put that behavior behind useDeprecatedResultNormalization, use it explicitly for now, and then announce that we're changing the default.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Err sorry, I guess transform + untransform would become the behavior when useDeprecatedResultNormalization is false. You would explicitly set it to false in your new tests for now, and then we can make it part of this announcement and then change the default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, let me update. And yeah easier to work with than dealing with a new helper function, thanks for pointing me here to have another look at the code.

Copy link
Contributor Author

@oleg-codaio oleg-codaio Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated! Using this in https://github.com/coda/packs/pull/4494.

@@ -380,8 +380,8 @@ function unmapKeys(obj: {[key: string]: any}, schema?: Schema): object {

export function untransformBody(body: any, schema: Schema | undefined): any {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we had a bug here compared to what transformBody does (cc @chris-codaio).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this manifest itself? Will this break any existing behavior related to 2-way sync?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't able to repro that code path with 2-way sync but I did update one place where we have test coverage here: https://github.com/coda/coda/pull/118340

@ekoleda-codaio
Copy link
Contributor

LGTM. I'm not terribly clear on what the delta is for the Pack developer, but I don't see anything to object over. I'm not familiar enough with the implementation to approve the PR, so leaving that to others.

Copy link
Collaborator

@jonathan-codaio jonathan-codaio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok would just flesh out the changelog though re context.fetcher.fetch.resolves() so that it's actionable for external developers.

@oleg-codaio oleg-codaio merged commit 8422fa6 into main Oct 7, 2024
1 check passed
@oleg-codaio oleg-codaio deleted the osv-types-mocking branch October 7, 2024 23:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants