-
Notifications
You must be signed in to change notification settings - Fork 948
Share Integration Tests between firestore-exp and the main SDK #3374
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
Conversation
🦋 Changeset is good to goLatest commit: b6abc27 We got this. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Binary Size ReportAffected SDKs
Test Logs
|
688c6e1
to
e162085
Compare
ca0261e
to
ddddda8
Compare
8dbe197
to
4cc627a
Compare
4cc627a
to
3f79ac7
Compare
3f79ac7
to
bcf91c6
Compare
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.
This seems like a lot of plumbing that ultimately serves to make the FirestoreShim stand on equal footing to the classic Firestore implementation. Is it possible to just make the FirestoreShim the actual implementation of classic Firestore? That way running one set of tests would verify both implementations, since the classic version is just a thin veneer over the exp implementation.
It seems like a potential stumbling block would be the difference in the way settings are handled, but it seems like we could handle that by just re-instantiating the underlying exp Firestore on settings change.
return firestore; | ||
} | ||
|
||
export function usesModularApi(): false { |
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.
"Modular" doesn't really cleanly describe the difference between the the Firestore-API-with-classes vs the tree-shakeable one.
The core of the difference seems to be class-based vs function-based. To me this suggests that this should be the basis of this kind of property.
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.
(No code updates yet).
The future plan for clients that are rewritten from scratch rather than replaced inline was to build a shim layer that implements the new API in terms of the old API. I essentially implemented this for our tests. There are some areas where the Shim does less work (e.g. validation), but it is pretty close to the model that @Feiyang1 had originally proposed for all SDKs.
I can add some of the validation to the Shim layer, which would mean we would run more tests. Even with that, it still feels really scary to me to replace our existing code with the shim (at least at this point in time).
I also have to rewrite all user data as the enter and leave the Shim, which we would need to optimize before our users are using the Shim.
Furthermore, I can reduce the amount of plumbing by not adding the test files to exp/test and instead just changing the test rules. Is that something I should explore?
Ultimately though, the model that was proposed was that the classic API would delegate to the new exp API. As proposed this PR doesn't do that; instead it leaves two parallel implementations that just happen to be testable via the same integration tests. I suppose what you're saying right now is that you don't have enough confidence in the exp API to make this swap, and that's fair. If the intent behind this PR is that this arrangement is temporary I'm more OK with it. I still think it's a lot of plumbing though.
Isn't this validation logic something we'd need in firestore-exp? If it's not needed there, why is it needed in the classic Firestore?
What is the source of this problem? Aren't things like Timestamps and GeoPoints the same in both implementations?
Re test rules, that seems reasonable. Part of my concern though is that test duration in the JS repo is already quite long, so essentially doubling the size of the integration test suite seems painful. Moving to a model where the classic API delegated to the functional API would allow you to test them both together (because the classic API would be the shim). |
I updated the name of
The goal of this PR is for now just to share the tests, not the surface. If we did share the surface, we wouldn't need to share the tests and wouldn't have to run them twice (which is something I hadn't considered).
@Feiyang1 and I have been talking about our input validation, as it adds a lot of overhead to the SDK. At the moment, I have only implemented the kind of validation we have in the other Firestore SDKs, which should prevent invalid state for syntactically valid input. There is an ongoing effort to come to a conclusion on our strategy for Web SDK input validation: go/jscore-input-validation If we added the input validation to the Shim layer and also implemented
FieldPath, FieldValue, and DocumentReference. FieldPath and FieldValue would be relatively trivial to accept without rewriting, since they are input-only types. |
PTAL :) Thanks. |
"pregendeps:lite": "yarn build:lite", | ||
"gendeps:lite": "../../scripts/exp/extract-deps.sh --types ./lite/index.d.ts --bundle ./dist/lite/index.node.esm2017.js --output ./lite/test/dependencies.json", | ||
"test:exp": "TS_NODE_CACHE=NO TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha 'exp/test/**/*.test.ts' --file exp/index.node.ts --config ../../config/mocharc.node.js", | ||
"test:exp": "TS_NODE_CACHE=NO TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha 'test/integration/api/*.test.ts' --file exp/index.node.ts --config ../../config/mocharc.node.js", | ||
"test:exp:persistence": "USE_MOCK_PERSISTENCE=YES TS_NODE_CACHE=NO TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha 'test/integration/api/*.test.ts' --require ts-node/register --require exp/index.node.ts --require test/util/node_persistence.ts --config ../../config/mocharc.node.js", |
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.
These entries are borderline illegible. Is it worth pulling them out into scripts? (Feel free to ignore/defer until later.)
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.
I would say you are being nice here :) There are 100% illegible. I tried to create a script this morning, but I failed so I am going to tackle this later.
// FirestoreShim returns a new instance of FirebaseFirestore that is | ||
// semantically identical to the originating instance, but does not | ||
// compare equal using the default JavaScript semantics. | ||
expect(db.doc('foo/bar').firestore).to.be.an.instanceof(Firestore); |
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.
Is there a way we could define equality of Firestore instances based on e.g. the project, database, and app name?
I don't mean necessarily adding equals methods or something like that, but just an assertion we could use in tests? That way we could assert the Firestore instances are equivalent and use the same assertion for both cases.
As it stands, verifying that the thing returned is an instance of Firestore ... isn't much of a test.
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.
I changed the shim to pass the Firestore instance between types, which is likely what we need to to once we productize this code path. This change removes the need to special-case this here.
if (usesModularApi()) { | ||
// The modular API throws an exception rather than rejecting the | ||
// Promise, which matches our overall handling of API call violations. | ||
expect(() => firestore.clearPersistence()).to.throw(expectedError); |
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 this is the behavior we want, why not change the classic version to match?
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.
I think this meets the bar for "breaking change" since it throws instead of returning a rejected Promise.
}); | ||
}); | ||
}); | ||
// timestampInSnapshots is not support in the modular API. |
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.
Off topic: are we removing this option at Fireconf?
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.
I am planning to do so: go/firestore-breaking-changes
}); | ||
|
||
validationIt(persistence, 'enforces minimum cache size', db => { | ||
validationIt(persistence, 'enforces minimum cache size', () => { | ||
const db = newTestFirestore('testProjectId'); |
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.
This is an invalid project ID. Only lowercase, numbers, and dashes are allowed.
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.
Uses "test-project" here and elsewhere (via a new TEST_PROJECT export).
'Function CollectionReference.doc() requires between 0 and ' + | ||
'1 arguments, but was called with 2 arguments.' | ||
); | ||
if (usesModularApi()) { |
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.
Since the only differences in the error messages are the function name and argument position, it seems like we could redefine these tests as the common set and those that are additional for the classic API. As it stands there's nothing requiring any of the equivalent validation checks to be identical. Given their superficial dissimilarity it seems possible for someone to overlook that a message needs to be updated in both places.
I'm not actually sure this is a good idea, but I thought I'd mention the idea to see if it resonates with you at all.
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.
Done. This should also go away as we productionize the shim.
const FieldPath = firebaseExport.FieldPath; | ||
const FieldValue = firebaseExport.FieldValue; | ||
const Timestamp = firebaseExport.Timestamp; | ||
const usesModularApi = firebaseExport.usesFunctionalApi; |
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.
Could we make this consistent throughout?
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.
Oops. Done.
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.
LGTM
6df3719
to
76a839a
Compare
This PR removes the custom integration tests for firestore-exp and changes the integration tests under
test/integration/api/
to be able to run against the firestore-exp SDK (which I started calling "modular SDK" in the code, but maybe I shouldn't do that).The logic is based on the FirestoreShim added in #3361
Couple things: