diff --git a/.eslintrc.yml b/.eslintrc.yml index ddd89bd6ef..451fd8d52f 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -483,6 +483,7 @@ rules: wrap-regex: off yield-star-spacing: off +ignorePatterns: 'integrationTests/ts/*.ts' overrides: - files: '**/*.ts' parser: '@typescript-eslint/parser' @@ -640,6 +641,16 @@ overrides: import/no-extraneous-dependencies: [error, { devDependencies: true }] import/no-nodejs-modules: off no-restricted-syntax: off + - files: 'integrationTests/**' + parserOptions: + sourceType: script + rules: + node/no-unpublished-import: off + node/no-unpublished-require: off + node/no-sync: off + import/no-extraneous-dependencies: [error, { devDependencies: true }] + import/no-nodejs-modules: off + no-console: off - files: 'resources/**' parserOptions: sourceType: script diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86458a87e1..e026256548 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,12 +49,38 @@ jobs: - name: Spellcheck run: npm run check:spelling + integrationTests: + name: Run integration tests + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: ${{ env.NODE_VERSION_USED_FOR_DEVELOPMENT }} + + - name: Cache Node.js modules + uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.OS }}-node- + + - name: Install Dependencies + run: npm ci + - name: Build NPM package run: npm run build:npm - name: Build Deno package run: npm run build:deno + - name: Run Integration Tests + run: npm run check:integrations + fuzz: name: Run fuzzing tests runs-on: ubuntu-latest @@ -178,7 +204,7 @@ jobs: github.event_name == 'push' && github.repository == 'graphql/graphql-js' && github.ref == 'refs/heads/master' - needs: [test, fuzz, lint] + needs: [test, fuzz, lint, integrationTests] steps: - name: Checkout repo uses: actions/checkout@v2 @@ -214,7 +240,7 @@ jobs: github.event_name == 'push' && github.repository == 'graphql/graphql-js' && github.ref == 'refs/heads/master' - needs: [test, fuzz, lint] + needs: [test, fuzz, lint, integrationTests] steps: - name: Checkout repo uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index 63ba9186f2..d474eb14ee 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,6 @@ coverage npmDist denoDist benchmarkDist +integrationTmp npm deno diff --git a/integrationTests/README.md b/integrationTests/README.md new file mode 100644 index 0000000000..706449103a --- /dev/null +++ b/integrationTests/README.md @@ -0,0 +1 @@ +# TBD diff --git a/integrationTests/integration-test.js b/integrationTests/integration-test.js new file mode 100644 index 0000000000..c64d6570ef --- /dev/null +++ b/integrationTests/integration-test.js @@ -0,0 +1,30 @@ +// @noflow + +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const childProcess = require('child_process'); + +const { describe, it } = require('mocha'); + +function exec(command, options = {}) { + return childProcess.execSync(command, { + stdio: 'inherit', + ...options, + }); +} + +describe('Integration Tests', () => { + const tmpDir = path.resolve('./integrationTmp'); + fs.rmdirSync(tmpDir, { recursive: true }); + fs.mkdirSync(tmpDir); + + it('Should compile with all supported TS versions', () => { + exec(`cp -R ${path.join(__dirname, 'ts')} ${tmpDir}`); + + const cwd = path.join(tmpDir, 'ts'); + exec('npm ci', { cwd }); + exec('npm test', { cwd }); + }).timeout(40000); +}); diff --git a/integrationTests/ts/index.ts b/integrationTests/ts/index.ts new file mode 100644 index 0000000000..7781e09b7f --- /dev/null +++ b/integrationTests/ts/index.ts @@ -0,0 +1,30 @@ +import { GraphQLString, GraphQLSchema, GraphQLObjectType } from 'graphql/type'; +import { ExecutionResult } from 'graphql/execution'; +import { graphqlSync } from 'graphql'; + +const queryType: GraphQLObjectType = new GraphQLObjectType({ + name: 'Query', + fields: { + sayHi: { + type: GraphQLString, + args: { + who: { type: GraphQLString }, + }, + resolve: (_root, args) => 'Hello ' + (args.who || 'World'), + }, + }, +}); + +const schema: GraphQLSchema = new GraphQLSchema({ + query: queryType, +}); + +const result: ExecutionResult = graphqlSync({ + schema, + source: ` + query helloWho($who: String){ + test(who: $who) + } + `, + variableValues: { who: 'Dolly' }, +}); diff --git a/integrationTests/ts/package-lock.json b/integrationTests/ts/package-lock.json new file mode 100644 index 0000000000..27f52bd580 --- /dev/null +++ b/integrationTests/ts/package-lock.json @@ -0,0 +1,85 @@ +{ + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/node": { + "version": "10.12.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.21.tgz", + "integrity": "sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ==" + }, + "graphql": { + "version": "file:../../npmDist" + }, + "typescript-2.6": { + "version": "npm:typescript@2.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", + "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=" + }, + "typescript-2.7": { + "version": "npm:typescript@2.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz", + "integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==" + }, + "typescript-2.8": { + "version": "npm:typescript@2.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.8.4.tgz", + "integrity": "sha512-IIU5cN1mR5J3z9jjdESJbnxikTrEz3lzAw/D0Tf45jHpBp55nY31UkUvmVHoffCfKHTqJs3fCLPDxknQTTFegQ==" + }, + "typescript-2.9": { + "version": "npm:typescript@2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==" + }, + "typescript-3.0": { + "version": "npm:typescript@3.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.0.3.tgz", + "integrity": "sha512-kk80vLW9iGtjMnIv11qyxLqZm20UklzuR2tL0QAnDIygIUIemcZMxlMWudl9OOt76H3ntVzcTiddQ1/pAAJMYg==" + }, + "typescript-3.1": { + "version": "npm:typescript@3.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz", + "integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==" + }, + "typescript-3.2": { + "version": "npm:typescript@3.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz", + "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==" + }, + "typescript-3.3": { + "version": "npm:typescript@3.3.4000", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.4000.tgz", + "integrity": "sha512-jjOcCZvpkl2+z7JFn0yBOoLQyLoIkNZAs/fYJkUG6VKy6zLPHJGfQJYFHzibB6GJaF/8QrcECtlQ5cpvRHSMEA==" + }, + "typescript-3.4": { + "version": "npm:typescript@3.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", + "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==" + }, + "typescript-3.5": { + "version": "npm:typescript@3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==" + }, + "typescript-3.6": { + "version": "npm:typescript@3.6.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.5.tgz", + "integrity": "sha512-BEjlc0Z06ORZKbtcxGrIvvwYs5hAnuo6TKdNFL55frVDlB+na3z5bsLhFaIxmT+dPWgBIjMo6aNnTOgHHmHgiQ==" + }, + "typescript-3.7": { + "version": "npm:typescript@3.7.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", + "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==" + }, + "typescript-3.8": { + "version": "npm:typescript@3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==" + }, + "typescript-3.9": { + "version": "npm:typescript@3.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", + "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==" + } + } +} diff --git a/integrationTests/ts/package.json b/integrationTests/ts/package.json new file mode 100644 index 0000000000..f9c970ae26 --- /dev/null +++ b/integrationTests/ts/package.json @@ -0,0 +1,26 @@ +{ + "version": "1.0.0", + "scripts": { + "test": "node test.js", + "test-3.8": "tsc test.ts", + "test-3.9": "tsc test.ts" + }, + "dependencies": { + "@types/node": "10.12.21", + "graphql": "file:../../npmDist", + "typescript-2.6": "npm:typescript@2.6.x", + "typescript-2.7": "npm:typescript@2.7.x", + "typescript-2.8": "npm:typescript@2.8.x", + "typescript-2.9": "npm:typescript@2.9.x", + "typescript-3.0": "npm:typescript@3.0.x", + "typescript-3.1": "npm:typescript@3.1.x", + "typescript-3.2": "npm:typescript@3.2.x", + "typescript-3.3": "npm:typescript@3.3.x", + "typescript-3.4": "npm:typescript@3.4.x", + "typescript-3.5": "npm:typescript@3.5.x", + "typescript-3.6": "npm:typescript@3.6.x", + "typescript-3.7": "npm:typescript@3.7.x", + "typescript-3.8": "npm:typescript@3.8.x", + "typescript-3.9": "npm:typescript@3.9.x" + } +} diff --git a/integrationTests/ts/test.js b/integrationTests/ts/test.js new file mode 100644 index 0000000000..a8bd1ef9ca --- /dev/null +++ b/integrationTests/ts/test.js @@ -0,0 +1,19 @@ +// @noflow + +'use strict'; + +const path = require('path'); +const childProcess = require('child_process'); + +const { dependencies } = require('./package.json'); + +const tsVersions = Object.keys(dependencies) + .filter((pkg) => pkg.startsWith('typescript-')) + .sort((a, b) => b.localeCompare(a)); + +for (const version of tsVersions) { + console.log(`Testing on ${version} ...`); + + const tscPath = path.join(__dirname, 'node_modules', version, 'bin/tsc'); + childProcess.execSync(tscPath, { stdio: 'inherit' }); +} diff --git a/integrationTests/ts/tsconfig.json b/integrationTests/ts/tsconfig.json new file mode 100644 index 0000000000..ea6266120c --- /dev/null +++ b/integrationTests/ts/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": ["es6", "esnext.asynciterable"], + "strict": true, + "noEmit": true, + "types": [] + } +} diff --git a/package.json b/package.json index af217a6d28..b9cfbc351d 100644 --- a/package.json +++ b/package.json @@ -32,14 +32,15 @@ "fuzzonly": "mocha --full-trace src/**/__tests__/**/*-fuzz.js", "testonly": "mocha --full-trace src/**/__tests__/**/*-test.js", "testonly:cover": "nyc npm run testonly", - "lint": "eslint --cache --ext .js,.ts src resources", + "lint": "eslint --cache --ext .js,.ts src resources integrationTests", "benchmark": "node --noconcurrent_sweeping --expose-gc --predictable ./resources/benchmark.js", "prettier": "prettier --ignore-path .gitignore --write --list-different \"**/*.{js,ts,md,json,yml}\"", "prettier:check": "prettier --ignore-path .gitignore --check \"**/*.{js,ts,md,json,yml}\"", "check": "flow check", "check:ts": "dtslint src", "check:cover": "node resources/check-cover.js && nyc report --nycrc-path .nycflowrc.yml", - "check:spelling": "cspell \"./{src/**/,resources/**/}*.{js,ts,md,graphql}\"", + "check:spelling": "cspell \"./{src/**/,resources/**/,integrationTests/**/}*.{js,ts,md,graphql}\"", + "check:integrations": "mocha --full-trace integrationTests/*-test.js", "build:npm": "node resources/build-npm.js", "build:deno": "node resources/build-deno.js", "changelog": "node resources/gen-changelog.js",