Skip to content

Commit

Permalink
Upgrade TypeScript and typecheck tests
Browse files Browse the repository at this point in the history
Upgrading to TS 4 is generally useful, but it also lets use combine `composite`
with `noEmit`, which lets us actually use `tsconfig.test.json`.

This PR copies a few things we've done recently in the Federation repo.

- Upgrade TypeScript, Jest, and Codecov.
- Drop jest-cucumber dep (hasn't been used for a while).
- Update VSCode task to use the "typescript" type.
- Set enablePromptUseWorkspaceTsdk like in
  apollographql/federation#728
- Stop using moduleNameMapper in jest config, which seemed to create weird
  issues. Instead, just make sure that `npm run compile` happens before you
  run tests (at least when run via `npm test`) via a `pretest` script.
- Fix a lot of compilation errors (mostly caused by actually typechecking tests,
  though some from the upgrade). Most of this is pretty localized, but some
  required more work (eg, replacing a `Map` that was being treated as a
  `KeyValueCache` with an actual `KeyValueCache` implementation).
- I found the moduleNameMapper pulling in a top-level `__mocks__` to be
  confusing and also led to errors about trying to import files from outside a
  project. In fact in general I found `__mocks__` to be confusing. So:
  - I replaced our use of a custom `Date` mocker plus `jest.useFakeTimers` with
    `@sinonjs/fake-timers` (which does both and is what jest's is built on)
  - Replaced `__mocks__/apollo-server-env.ts` with a file that doesn't have
    a special `__mocks__` name
  - Did the same for the ioredis mock, and loaded it into `jest.mock` explicitly
    rather than implicitly
- The thing where we imported a function that defined a jest test suite from the
  `__tests__` of `apollo-server-caching` was sort of weird already, and
  importing from a project that used `noEmit` didn't seem to work at all
  here. So I changed the testing function to just be a normal non-Jest-specific
  function exported from `apollo-server-caching` that can be used in Jest tests
  (or non-Jest tests for that matter) with a bit of preamble. (I changed its
  name too so it's obviously a different function.) Because closing the cache is
  now not part of the test, we didn't need `TestableKeyValueCache` any more so I
  dropped it.
- isDirectiveDefined isn't exported and is now always called with an array, so
  remove code that runs if it doesn't get one and tests that that code works.
- RESTDataSource used to document and test that you can override `baseURL` in a
  subclass with a getter. This is illegal in TS4 so we don't officially support
  it any more.

Additionally, this PR removes global types from `apollo-server-env` (the
`global.d.ts` file). Thanks to @martijnwalraven for figuring this out and
writing the following:

We use exports from `apollo-server-env` to access the Fetch API to avoid
depending on running in specific environments. While environments like
Cloudflare Workers and Deno expose a Fetch API globally, in Node environments
you'd generally like to avoid polyfilling the global context. There are also
differences between the APIs available in these environments that we may want to
account for with our own types.

Unfortunately,`apollo-fetch` uses `cross-fetch` as a global polyfill (see
https://github.com/apollographql/apollo-fetch/blob/0a0b8df241960dfa72abf3bd179e9d936265a7da/packages/apollo-fetch/src/apollo-fetch.ts#L17),
and expects having Fetch API types defined globally.

Because we use `apollo-fetch` in our tests, we've long used a `global.d.ts` in
`apollo-server-env` to make the exported types available globally without
depending on the `dom` lib types (because most of the types in there don't
really make sense in non-browser environments and can lead to accidental usage).

As it turns out however, we also use `superagent` in our tests, and
`@types/superagent` now specifies an explicit dependency on `dom` lib. As
TypeScript makes any global type declarations available throughout a project,
that means our tests now get the `dom` lib types merged into their environment,
resulting in conflicts with the types in `apollo-server-env`'s `global.d.ts`.

Forcing anyone depending on packages like `@types/superagent` to have their
environment extended with the `dom` lib types isn't great, and there are
existing discussions about the implications of this for that package
specifically (see DefinitelyTyped/DefinitelyTyped#41425). There is also a
promising proposal for a `strictEnvironment` option in TypeScript that would
help avoid these situations (see
https://gist.github.com/RyanCavanaugh/702ebd1ca2fc060e58e634b4e30c1c1c).

For now, I've solved this by reluctantly adding `dom` to
`tsconfig.test.base.json`. We should be able to remove this when our
dependencies get fixed or if `strictEnvironment` gets implemented.

I also fixed some typing issues that ironically illustrate the danger of having
these `dom` types available. Because the mocked version of `apollo-server-env`
exported classes through a `const` declaration, that didn't actually export them
as types, just as values (see microsoft/TypeScript#36348). But because we have
similarly named types defined in `dom`, those were used instead. Using named
exports in the `apollo-server-env` mock avoids this.

Fixes #5119.
  • Loading branch information
glasser committed May 4, 2021
1 parent 32cfdcf commit 39263a3
Show file tree
Hide file tree
Showing 88 changed files with 1,024 additions and 6,297 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"editor.wordWrapColumn": 80,
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"typescript.tsdk": "./node_modules/typescript/lib"
"typescript.tsdk": "./node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
48 changes: 23 additions & 25 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "TypeScript watch",
"type": "shell",
"command": "./node_modules/.bin/tsc",
"args": [
"--build",
"tsconfig.build.json",
"--watch"
],
"isBackground": true,
"problemMatcher": [
"$tsc-watch"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "never",
"panel": "dedicated"
}
}
]
"version": "2.0.0",
"tasks": [
{
"label": "TypeScript watch",
"type": "typescript",
"tsconfig": "tsconfig.json",
"option": "watch",
"problemMatcher": ["$tsc-watch"],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "never",
"revealProblems": "never",
"panel": "shared",
"clear": true
},
"runOptions": {
"runOn": "folderOpen"
}
}
]
}
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ The version headers in this history reflect the versions of Apollo Server itself
- The `graphql-extensions` API (e.g., `GraphQLExtensions`, `extensions`) has been dropped in favor of the new [plugins API](https://www.apollographql.com/docs/apollo-server/integrations/plugins/).
- In order to let the `graphql-upload` package evolve on its own, uploads are no longer integrated directly with Apollo Server. To bring them back in their current form, see [the migration guide section on File Uploads](./docs/source/migration.md#File-uploads)
- Removed deprecated `ApolloServer.schema` field, which never worked with gateways. If you'd like to extract your schema from your server, make a plugin with `serverWillStart`, or register `onSchemaChange` on your gateway.
- `apollo-server-caching`: The test suite helper works differently, and the `TestableKeyValueCache` interface is removed.
- `apollo-datasource-rest`: We no longer officially support overriding the `baseURL` property with a getter, because TypeScript 4 does not allow you to do that.
- Top-level exports have changed. E.g.,

- We no longer re-export the entirety of `graphql-tools` (including `makeExecutableSchema`) from all Apollo Server packages.
Expand Down
32 changes: 0 additions & 32 deletions __mocks__/date.ts

This file was deleted.

14 changes: 1 addition & 13 deletions docs/source/data/data-sources.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -305,19 +305,7 @@ class PersonalizationAPI extends RESTDataSource {

### Resolving URLs dynamically

In some cases, you'll want to set your REST API's base URL based on the environment or other contextual values. You can use a getter for this:

```js
get baseURL() {
if (this.context.env === 'development') {
return 'https://movies-api-dev.example.com/';
} else {
return 'https://movies-api.example.com/';
}
}
```

If you need more customization, including the ability to resolve a URL asynchronously, you can also override `resolveURL`:
In some cases, you'll want to set the URL based on the environment or other contextual values. To do this, you can override `resolveURL`:

```js
async resolveURL(request: RequestOptions) {
Expand Down
10 changes: 0 additions & 10 deletions jest.config.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,6 @@ module.exports = {
"/dist/"
],
moduleFileExtensions: [...defaults.moduleFileExtensions, "ts", "tsx"],
moduleNameMapper: {
'^__mocks__/(.*)$': '<rootDir>/../../__mocks__/$1',
// This regex should match the packages that we want compiled from source
// through `ts-jest`, as opposed to loaded from their output files in
// `dist`.
// We don't want to match `apollo-server-env` and
// `apollo-reporting-protobuf`, because these don't depend on
// compilation but need to be initialized from as parto of `prepare`.
'^(?!apollo-server-env|apollo-reporting-protobuf)(apollo-(?:server|datasource|cache-control|tracing)[^/]*)(?:/dist)?((?:/.*)|$)': '<rootDir>/../../packages/$1/src$2'
},
clearMocks: true,
globals: {
"ts-jest": {
Expand Down
Loading

0 comments on commit 39263a3

Please sign in to comment.