Repository: graphql/graphql-js
Pull request #3288 (2021-10-05 09:04:53)

Move validation of names into `GraphQL*` constructors


Patch:
diff --git a/src/index.ts b/src/index.ts
index c09efb04..d3641deb 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -126,6 +126,9 @@ export {
   /** Validate GraphQL schema. */
   validateSchema,
   assertValidSchema,
+  /** Upholds the spec rules about naming. */
+  assertName,
+  assertEnumValueName,
 } from './type/index';
 
 export type {
diff --git a/src/type/assertName.ts b/src/type/assertName.ts
new file mode 100644
index 00000000..c4436191
--- /dev/null
+++ b/src/type/assertName.ts
@@ -0,0 +1,44 @@
+import { devAssert } from '../jsutils/devAssert';
+
+import { GraphQLError } from '../error/GraphQLError';
+import { isNameStart, isNameContinue } from '../language/characterClasses';
+
+/**
+ * Upholds the spec rules about naming.
+ */
+export function assertName(name: string): string {
+  devAssert(name != null, 'Must provide name.');
+  devAssert(typeof name === 'string', 'Expected name to be a string.');
+
+  if (name.length === 0) {
+    throw new GraphQLError('Expected name to be a non-empty string.');
+  }
+
+  for (let i = 1; i < name.length; ++i) {
+    if (!isNameContinue(name.charCodeAt(i))) {
+      throw new GraphQLError(
+        `Names must only contain [_a-zA-Z0-9] but "${name}" does not.`,
+      );
+    }
+  }
+
+  if (!isNameStart(name.charCodeAt(0))) {
+    throw new GraphQLError(
+      `Names must start with [_a-zA-Z] but "${name}" does not.`,
+    );
+  }
+
+  return name;
+}
+
+/**
+ * Upholds the spec rules about naming enum values.
+ *
+ * @internal
+ */
+export function assertEnumValueName(name: string): string {
+  if (name === 'true' || name === 'false' || name === 'null') {
+    throw new GraphQLError(`Enum values cannot be named: ${name}`);
+  }
+  return assertName(name);
+}
diff --git a/src/type/definition.ts b/src/type/definition.ts
index ab3dfcfc..11bc335f 100644
--- a/src/type/definition.ts
+++ b/src/type/definition.ts
@@ -43,6 +43,7 @@ import type {
 import { valueFromASTUntyped } from '../utilities/valueFromASTUntyped';
 
 import type { GraphQLSchema } from './schema';
+import { assertName, assertEnumValueName } from './assertName';
 
 // Predicates & Assertions
 
@@ -595,7 +596,7 @@ export class GraphQLScalarType<TInternal = unknown, TExternal = TInternal> {
       config.parseValue ??
       (identityFunc as GraphQLScalarValueParser<TInternal>);
 
-    this.name = config.name;
+    this.name = assertName(config.name);
     this.description = config.description;
     this.specifiedByURL = config.specifiedByURL;
     this.serialize =
@@ -608,8 +609,6 @@ export class GraphQLScalarType<TInternal = unknown, TExternal = TInternal> {
     this.astNode = config.astNode;
     this.extensionASTNodes = config.extensionASTNodes ?? [];
 
-    devAssert(typeof config.name === 'string', 'Must provide name.');
-
     devAssert(
       config.specifiedByURL == null ||
         typeof config.specifiedByURL === 'string',
@@ -763,7 +762,7 @@ export class GraphQLObjectType<TSource = any, TContext = any> {
   private _interfaces: ThunkReadonlyArray<GraphQLInterfaceType>;
 
   constructor(config: Readonly<GraphQLObjectTypeConfig<TSource, TContext>>) {
-    this.name = config.name;
+    this.name = assertName(config.name);
     this.description = config.description;
     this.isTypeOf = config.isTypeOf;
     this.extensions = toObjMap(config.extensions);
@@ -772,7 +771,6 @@ export class GraphQLObjectType<TSource = any, TContext = any> {
 
     this._fields = () => defineFieldMap(config);
     this._interfaces = () => defineInterfaces(config);
-    devAssert(typeof config.name === 'string', 'Must provide name.');
     devAssert(
       config.isTypeOf == null || typeof config.isTypeOf === 'function',
       `${this.name} must provide "isTypeOf" as a function, ` +
@@ -863,7 +861,7 @@ function defineFieldMap<TSource, TContext>(
     );
 
     return {
-      name: fieldName,
+      name: assertName(fieldName),
       description: fieldConfig.description,
       type: fieldConfig.type,
       args: defineArguments(argsConfig),
@@ -880,7 +878,7 @@ export function defineArguments(
   config: GraphQLFieldConfigArgumentMap,
 ): ReadonlyArray<GraphQLArgument> {
   return Object.entries(config).map(([argName, argConfig]) => ({
-    name: argName,
+    name: assertName(argName),
     description: argConfig.description,
     type: argConfig.type,
     defaultValue: argConfig.defaultValue,
@@ -1129,7 +1127,7 @@ export class GraphQLInterfaceType {
   private _interfaces: ThunkReadonlyArray<GraphQLInterfaceType>;
 
   constructor(config: Readonly<GraphQLInterfaceTypeConfig<any, any>>) {
-    this.name = config.name;
+    this.name = assertName(config.name);
     this.description = config.description;
     this.resolveType = config.resolveType;
     this.extensions = toObjMap(config.extensions);
@@ -1138,7 +1136,6 @@ export class GraphQLInterfaceType {
 
     this._fields = defineFieldMap.bind(undefined, config);
     this._interfaces = defineInterfaces.bind(undefined, config);
-    devAssert(typeof config.name === 'string', 'Must provide name.');
     devAssert(
       config.resolveType == null || typeof config.resolveType === 'function',
       `${this.name} must provide "resolveType" as a function, ` +
@@ -1258,7 +1255,7 @@ export class GraphQLUnionType {
   private _types: ThunkReadonlyArray<GraphQLObjectType>;
 
   constructor(config: Readonly<GraphQLUnionTypeConfig<any, any>>) {
-    this.name = config.name;
+    this.name = assertName(config.name);
     this.description = config.description;
     this.resolveType = config.resolveType;
     this.extensions = toObjMap(config.extensions);
@@ -1266,7 +1263,6 @@ export class GraphQLUnionType {
     this.extensionASTNodes = config.extensionASTNodes ?? [];
 
     this._types = defineTypes.bind(undefined, config);
-    devAssert(typeof config.name === 'string', 'Must provide name.');
     devAssert(
       config.resolveType == null || typeof config.resolveType === 'function',
       `${this.name} must provide "resolveType" as a function, ` +
@@ -1387,7 +1383,7 @@ export class GraphQLEnumType /* <T> */ {
   private _nameLookup: ObjMap<GraphQLEnumValue>;
 
   constructor(config: Readonly<GraphQLEnumTypeConfig /* <T> */>) {
-    this.name = config.name;
+    this.name = assertName(config.name);
     this.description = config.description;
     this.extensions = toObjMap(config.extensions);
     this.astNode = config.astNode;
@@ -1398,8 +1394,6 @@ export class GraphQLEnumType /* <T> */ {
       this._values.map((enumValue) => [enumValue.value, enumValue]),
     );
     this._nameLookup = keyMap(this._values, (value) => value.name);
-
-    devAssert(typeof config.name === 'string', 'Must provide name.');
   }
 
   getValues(): ReadonlyArray<GraphQLEnumValue /* <T> */> {
@@ -1526,7 +1520,7 @@ function defineEnumValues(
         `representing an internal value but got: ${inspect(valueConfig)}.`,
     );
     return {
-      name: valueName,
+      name: assertEnumValueName(valueName),
       description: valueConfig.description,
       value: valueConfig.value !== undefined ? valueConfig.value : valueName,
       deprecationReason: valueConfig.deprecationReason,
@@ -1627,14 +1621,13 @@ export class GraphQLInputObjectType {
   private _fields: ThunkObjMap<GraphQLInputField>;
 
   constructor(config: Readonly<GraphQLInputObjectTypeConfig>) {
-    this.name = config.name;
+    this.name = assertName(config.name);
     this.description = config.description;
     this.extensions = toObjMap(config.extensions);
     this.astNode = config.astNode;
     this.extensionASTNodes = config.extensionASTNodes ?? [];
 
     this._fields = defineInputFieldMap.bind(undefined, config);
-    devAssert(typeof config.name === 'string', 'Must provide name.');
   }
 
   getFields(): GraphQLInputFieldMap {
@@ -1692,7 +1685,7 @@ function defineInputFieldMap(
     );
 
     return {
-      name: fieldName,
+      name: assertName(fieldName),
       description: fieldConfig.description,
       type: fieldConfig.type,
       defaultValue: fieldConfig.defaultValue,
diff --git a/src/type/directives.ts b/src/type/directives.ts
index 0179c729..5375746d 100644
--- a/src/type/directives.ts
+++ b/src/type/directives.ts
@@ -13,6 +13,7 @@ import type {
   GraphQLArgument,
   GraphQLFieldConfigArgumentMap,
 } from './definition';
+import { assertName } from './assertName';
 import { GraphQLString, GraphQLBoolean } from './scalars';
 import {
   defineArguments,
@@ -63,14 +64,13 @@ export class GraphQLDirective {
   astNode: Maybe<DirectiveDefinitionNode>;
 
   constructor(config: Readonly<GraphQLDirectiveConfig>) {
-    this.name = config.name;
+    this.name = assertName(config.name);
     this.description = config.description;
     this.locations = config.locations;
     this.isRepeatable = config.isRepeatable ?? false;
     this.extensions = toObjMap(config.extensions);
     this.astNode = config.astNode;
 
-    devAssert(config.name, 'Directive must be named.');
     devAssert(
       Array.isArray(config.locations),
       `@${config.name} locations must be an Array.`,
diff --git a/src/type/index.ts b/src/type/index.ts
index 5686fd71..2561426b 100644
--- a/src/type/index.ts
+++ b/src/type/index.ts
@@ -176,3 +176,6 @@ export {
 
 /** Validate GraphQL schema. */
 export { validateSchema, assertValidSchema } from './validate';
+
+/** Upholds the spec rules about naming. */
+export { assertName, assertEnumValueName } from './assertName';
diff --git a/src/type/validate.ts b/src/type/validate.ts
index 77420d8b..b949365a 100644
--- a/src/type/validate.ts
+++ b/src/type/validate.ts
@@ -2,7 +2,6 @@ import { inspect } from '../jsutils/inspect';
 import type { Maybe } from '../jsutils/Maybe';
 
 import { GraphQLError } from '../error/GraphQLError';
-import { locatedError } from '../error/locatedError';
 
 import type {
   ASTNode,
@@ -17,7 +16,6 @@ import type {
   UnionTypeExtensionNode,
 } from '../language/ast';
 
-import { isValidNameError } from '../utilities/assertValidName';
 import { isEqualType, isTypeSubTypeOf } from '../utilities/typeComparators';
 
 import type { GraphQLSchema } from './schema';
@@ -104,11 +102,7 @@ class SchemaValidationContext {
     const _nodes = Array.isArray(nodes)
       ? (nodes.filter(Boolean) as ReadonlyArray<ASTNode>)
       : (nodes as Maybe<ASTNode>);
-    this.addError(new GraphQLError(message, _nodes));
-  }
-
-  addError(error: GraphQLError): void {
-    this._errors.push(error);
+    this._errors.push(new GraphQLError(message, _nodes));
   }
 
   getErrors(): ReadonlyArray<GraphQLError> {
@@ -205,9 +199,11 @@ function validateName(
   node: { readonly name: string; readonly astNode: Maybe<ASTNode> },
 ): void {
   // Ensure names are valid, however introspection types opt out.
-  const error = isValidNameError(node.name);
-  if (error) {
-    context.addError(locatedError(error, node.astNode));
+  if (node.name.startsWith('__')) {
+    context.reportError(
+      `Name "${node.name}" must not begin with "__", which is reserved by GraphQL introspection.`,
+      node.astNode,
+    );
   }
 }
 
@@ -498,16 +494,8 @@ function validateEnumValues(
   }
 
   for (const enumValue of enumValues) {
-    const valueName = enumValue.name;
-
     // Ensure valid name.
     validateName(context, enumValue);
-    if (valueName === 'true' || valueName === 'false' || valueName === 'null') {
-      context.reportError(
-        `Enum type ${enumType.name} cannot include value: ${valueName}.`,
-        enumValue.astNode,
-      );
-    }
   }
 }
 
diff --git a/src/utilities/assertValidName.ts b/src/utilities/assertValidName.ts
index 988a8efa..45c30ff4 100644
--- a/src/utilities/assertValidName.ts
+++ b/src/utilities/assertValidName.ts
@@ -1,11 +1,14 @@
 import { devAssert } from '../jsutils/devAssert';
 
 import { GraphQLError } from '../error/GraphQLError';
-import { isNameStart, isNameContinue } from '../language/characterClasses';
+
+import { assertName } from '../type/assertName';
 
 /**
  * Upholds the spec rules about naming.
+ * @deprecated Please use `assertName` instead. Will be removed in v17
  */
+// istanbul ignore next (Deprecated code)
 export function assertValidName(name: string): string {
   const error = isValidNameError(name);
   if (error) {
@@ -16,7 +19,9 @@ export function assertValidName(name: string): string {
 
 /**
  * Returns an Error if a name is invalid.
+ * @deprecated Please use `assertName` instead. Will be removed in v17
  */
+// istanbul ignore next (Deprecated code)
 export function isValidNameError(name: string): GraphQLError | undefined {
   devAssert(typeof name === 'string', 'Expected name to be a string.');
 
@@ -26,21 +31,9 @@ export function isValidNameError(name: string): GraphQLError | undefined {
     );
   }
 
-  if (name.length === 0) {
-    return new GraphQLError('Expected name to be a non-empty string.');
-  }
-
-  for (let i = 1; i < name.length; ++i) {
-    if (!isNameContinue(name.charCodeAt(i))) {
-      return new GraphQLError(
-        `Names must only contain [_a-zA-Z0-9] but "${name}" does not.`,
-      );
-    }
-  }
-
-  if (!isNameStart(name.charCodeAt(0))) {
-    return new GraphQLError(
-      `Names must start with [_a-zA-Z] but "${name}" does not.`,
-    );
+  try {
+    assertName(name);
+  } catch (error) {
+    return error;
   }
 }


Test patch:
diff --git a/src/type/__tests__/assertName-test.ts b/src/type/__tests__/assertName-test.ts
new file mode 100644
index 00000000..5bc1a12b
--- /dev/null
+++ b/src/type/__tests__/assertName-test.ts
@@ -0,0 +1,71 @@
+import { expect } from 'chai';
+import { describe, it } from 'mocha';
+
+import { assertName, assertEnumValueName } from '../assertName';
+import { assertValidName } from '../../utilities/assertValidName';
+
+describe('assertValidName()', () => {
+  assertValidName('test');
+  it('passthrough valid name', () => {
+    expect(assertName('_ValidName123')).to.equal('_ValidName123');
+  });
+
+  it('throws for non-strings', () => {
+    // @ts-expect-error
+    expect(() => assertName({})).to.throw('Expected name to be a string.');
+  });
+
+  it('throws on empty strings', () => {
+    expect(() => assertName('')).to.throw(
+      'Expected name to be a non-empty string.',
+    );
+  });
+
+  it('throws for names with invalid characters', () => {
+    expect(() => assertName('>--()-->')).to.throw(
+      'Names must only contain [_a-zA-Z0-9] but ">--()-->" does not.',
+    );
+  });
+
+  it('throws for names starting with invalid characters', () => {
+    expect(() => assertName('42MeaningsOfLife')).to.throw(
+      'Names must start with [_a-zA-Z] but "42MeaningsOfLife" does not.',
+    );
+  });
+});
+
+describe('assertEnumValueName()', () => {
+  it('passthrough valid name', () => {
+    expect(assertEnumValueName('_ValidName123')).to.equal('_ValidName123');
+  });
+
+  it('throws on empty strings', () => {
+    expect(() => assertEnumValueName('')).to.throw(
+      'Expected name to be a non-empty string.',
+    );
+  });
+
+  it('throws for names with invalid characters', () => {
+    expect(() => assertEnumValueName('>--()-->')).to.throw(
+      'Names must only contain [_a-zA-Z0-9] but ">--()-->" does not.',
+    );
+  });
+
+  it('throws for names starting with invalid characters', () => {
+    expect(() => assertEnumValueName('42MeaningsOfLife')).to.throw(
+      'Names must start with [_a-zA-Z] but "42MeaningsOfLife" does not.',
+    );
+  });
+
+  it('throws for restricted names', () => {
+    expect(() => assertEnumValueName('true')).to.throw(
+      'Enum values cannot be named: true',
+    );
+    expect(() => assertEnumValueName('false')).to.throw(
+      'Enum values cannot be named: false',
+    );
+    expect(() => assertEnumValueName('null')).to.throw(
+      'Enum values cannot be named: null',
+    );
+  });
+});
diff --git a/src/type/__tests__/definition-test.ts b/src/type/__tests__/definition-test.ts
index 0b73a021..9de80c07 100644
--- a/src/type/__tests__/definition-test.ts
+++ b/src/type/__tests__/definition-test.ts
@@ -324,9 +324,10 @@ describe('Type System: Objects', () => {
     expect(() => objType.getFields()).to.not.throw();
   });
 
-  it('rejects an Object type without name', () => {
-    // @ts-expect-error
-    expect(() => new GraphQLObjectType({})).to.throw('Must provide name.');
+  it('rejects an Object type with invalid name', () => {
+    expect(
+      () => new GraphQLObjectType({ name: 'bad-name', fields: {} }),
+    ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
   });
 
   it('rejects an Object type field with undefined config', () => {
@@ -353,6 +354,18 @@ describe('Type System: Objects', () => {
     );
   });
 
+  it('rejects an Object type with incorrectly named fields', () => {
+    const objType = new GraphQLObjectType({
+      name: 'SomeObject',
+      fields: {
+        'bad-name': { type: ScalarType },
+      },
+    });
+    expect(() => objType.getFields()).to.throw(
+      'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.',
+    );
+  });
+
   it('rejects an Object type with a field function that returns incorrect type', () => {
     const objType = new GraphQLObjectType({
       name: 'SomeObject',
@@ -380,6 +393,23 @@ describe('Type System: Objects', () => {
     );
   });
 
+  it('rejects an Object type with incorrectly named field args', () => {
+    const objType = new GraphQLObjectType({
+      name: 'SomeObject',
+      fields: {
+        badField: {
+          type: ScalarType,
+          args: {
+            'bad-name': { type: ScalarType },
+          },
+        },
+      },
+    });
+    expect(() => objType.getFields()).to.throw(
+      'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.',
+    );
+  });
+
   it('rejects an Object type with incorrectly typed interfaces', () => {
     const objType = new GraphQLObjectType({
       name: 'SomeObject',
@@ -478,9 +508,10 @@ describe('Type System: Interfaces', () => {
     expect(implementing.getInterfaces()).to.deep.equal([InterfaceType]);
   });
 
-  it('rejects an Interface type without name', () => {
-    // @ts-expect-error
-    expect(() => new GraphQLInterfaceType({})).to.throw('Must provide name.');
+  it('rejects an Interface type with invalid name', () => {
+    expect(
+      () => new GraphQLInterfaceType({ name: 'bad-name', fields: {} }),
+    ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
   });
 
   it('rejects an Interface type with incorrectly typed interfaces', () => {
@@ -559,9 +590,10 @@ describe('Type System: Unions', () => {
     expect(unionType.getTypes()).to.deep.equal([]);
   });
 
-  it('rejects an Union type without name', () => {
-    // @ts-expect-error
-    expect(() => new GraphQLUnionType({})).to.throw('Must provide name.');
+  it('rejects an Union type with invalid name', () => {
+    expect(
+      () => new GraphQLUnionType({ name: 'bad-name', types: [] }),
+    ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
   });
 
   it('rejects an Union type with an incorrect type for resolveType', () => {
@@ -674,11 +706,10 @@ describe('Type System: Enums', () => {
     expect(enumType.getValue('BAR')).has.property('value', 20);
   });
 
-  it('rejects an Enum type without name', () => {
-    // @ts-expect-error
-    expect(() => new GraphQLEnumType({ values: {} })).to.throw(
-      'Must provide name.',
-    );
+  it('rejects an Enum type with invalid name', () => {
+    expect(
+      () => new GraphQLEnumType({ name: 'bad-name', values: {} }),
+    ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
   });
 
   it('rejects an Enum type with incorrectly typed values', () => {
@@ -692,6 +723,18 @@ describe('Type System: Enums', () => {
     ).to.throw('SomeEnum values must be an object with value names as keys.');
   });
 
+  it('rejects an Enum type with incorrectly named values', () => {
+    expect(
+      () =>
+        new GraphQLEnumType({
+          name: 'SomeEnum',
+          values: {
+            'bad-name': {},
+          },
+        }),
+    ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
+  });
+
   it('rejects an Enum type with missing value definition', () => {
     expect(
       () =>
@@ -761,10 +804,11 @@ describe('Type System: Input Objects', () => {
       });
     });
 
-    it('rejects an Input Object type without name', () => {
-      // @ts-expect-error
-      expect(() => new GraphQLInputObjectType({})).to.throw(
-        'Must provide name.',
+    it('rejects an Input Object type with invalid name', () => {
+      expect(
+        () => new GraphQLInputObjectType({ name: 'bad-name', fields: {} }),
+      ).to.throw(
+        'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.',
       );
     });
 
@@ -789,6 +833,18 @@ describe('Type System: Input Objects', () => {
         'SomeInputObject fields must be an object with field names as keys or a function which returns such an object.',
       );
     });
+
+    it('rejects an Input Object type with incorrectly named fields', () => {
+      const inputObjType = new GraphQLInputObjectType({
+        name: 'SomeInputObject',
+        fields: {
+          'bad-name': { type: ScalarType },
+        },
+      });
+      expect(() => inputObjType.getFields()).to.throw(
+        'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.',
+      );
+    });
   });
 
   describe('Input Object fields must not have resolvers', () => {
diff --git a/src/type/__tests__/directive-test.ts b/src/type/__tests__/directive-test.ts
index 3b481bd1..9496d57d 100644
--- a/src/type/__tests__/directive-test.ts
+++ b/src/type/__tests__/directive-test.ts
@@ -84,11 +84,10 @@ describe('Type System: Directive', () => {
     );
   });
 
-  it('rejects an unnamed directive', () => {
-    // @ts-expect-error
-    expect(() => new GraphQLDirective({ locations: ['QUERY'] })).to.throw(
-      'Directive must be named.',
-    );
+  it('rejects a directive with invalid name', () => {
+    expect(
+      () => new GraphQLDirective({ name: 'bad-name', locations: ['QUERY'] }),
+    ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
   });
 
   it('rejects a directive with incorrectly typed args', () => {
@@ -103,6 +102,19 @@ describe('Type System: Directive', () => {
     ).to.throw('@Foo args must be an object with argument names as keys.');
   });
 
+  it('rejects a directive with incorrectly named arg', () => {
+    expect(
+      () =>
+        new GraphQLDirective({
+          name: 'Foo',
+          locations: ['QUERY'],
+          args: {
+            'bad-name': { type: GraphQLString },
+          },
+        }),
+    ).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
+  });
+
   it('rejects a directive with undefined locations', () => {
     // @ts-expect-error
     expect(() => new GraphQLDirective({ name: 'Foo' })).to.throw(
diff --git a/src/type/__tests__/validation-test.ts b/src/type/__tests__/validation-test.ts
index 8325f694..a39f3a42 100644
--- a/src/type/__tests__/validation-test.ts
+++ b/src/type/__tests__/validation-test.ts
@@ -18,7 +18,6 @@ import type {
   GraphQLFieldConfig,
   GraphQLArgumentConfig,
   GraphQLInputFieldConfig,
-  GraphQLEnumValueConfigMap,
 } from '../definition';
 import { GraphQLSchema } from '../schema';
 import { GraphQLString } from '../scalars';
@@ -487,13 +486,15 @@ describe('Type System: Objects must have fields', () => {
     const schema = schemaWithFieldType(
       new GraphQLObjectType({
         name: 'SomeObject',
-        fields: { 'bad-name-with-dashes': { type: GraphQLString } },
+        fields: {
+          __badName: { type: GraphQLString },
+        },
       }),
     );
     expectJSON(validateSchema(schema)).to.deep.equal([
       {
         message:
-          'Names must only contain [_a-zA-Z0-9] but "bad-name-with-dashes" does not.',
+          'Name "__badName" must not begin with "__", which is reserved by GraphQL introspection.',
       },
     ]);
   });
@@ -525,7 +526,7 @@ describe('Type System: Fields args must be properly named', () => {
           badField: {
             type: GraphQLString,
             args: {
-              'bad-name-with-dashes': { type: GraphQLString },
+              __badName: { type: GraphQLString },
             },
           },
         },
@@ -535,7 +536,7 @@ describe('Type System: Fields args must be properly named', () => {
     expectJSON(validateSchema(schema)).to.deep.equal([
       {
         message:
-          'Names must only contain [_a-zA-Z0-9] but "bad-name-with-dashes" does not.',
+          'Name "__badName" must not begin with "__", which is reserved by GraphQL introspection.',
       },
     ]);
   });
@@ -956,51 +957,21 @@ describe('Type System: Enum types must be well defined', () => {
   });
 
   it('rejects an Enum type with incorrectly named values', () => {
-    function schemaWithEnum(values: GraphQLEnumValueConfigMap): GraphQLSchema {
-      return schemaWithFieldType(
-        new GraphQLEnumType({
-          name: 'SomeEnum',
-          values,
-        }),
-      );
-    }
-
-    const schema1 = schemaWithEnum({ '#value': {} });
-    expectJSON(validateSchema(schema1)).to.deep.equal([
-      {
-        message: 'Names must start with [_a-zA-Z] but "#value" does not.',
-      },
-    ]);
-
-    const schema2 = schemaWithEnum({ '1value': {} });
-    expectJSON(validateSchema(schema2)).to.deep.equal([
-      {
-        message: 'Names must start with [_a-zA-Z] but "1value" does not.',
-      },
-    ]);
+    const schema = schemaWithFieldType(
+      new GraphQLEnumType({
+        name: 'SomeEnum',
+        values: {
+          __badName: {},
+        },
+      }),
+    );
 
-    const schema3 = schemaWithEnum({ 'KEBAB-CASE': {} });
-    expectJSON(validateSchema(schema3)).to.deep.equal([
+    expectJSON(validateSchema(schema)).to.deep.equal([
       {
         message:
-          'Names must only contain [_a-zA-Z0-9] but "KEBAB-CASE" does not.',
+          'Name "__badName" must not begin with "__", which is reserved by GraphQL introspection.',
       },
     ]);
-
-    const schema4 = schemaWithEnum({ true: {} });
-    expectJSON(validateSchema(schema4)).to.deep.equal([
-      { message: 'Enum type SomeEnum cannot include value: true.' },
-    ]);
-
-    const schema5 = schemaWithEnum({ false: {} });
-    expectJSON(validateSchema(schema5)).to.deep.equal([
-      { message: 'Enum type SomeEnum cannot include value: false.' },
-    ]);
-
-    const schema6 = schemaWithEnum({ null: {} });
-    expectJSON(validateSchema(schema6)).to.deep.equal([
-      { message: 'Enum type SomeEnum cannot include value: null.' },
-    ]);
   });
 });
 
diff --git a/src/utilities/__tests__/assertValidName-test.ts b/src/utilities/__tests__/assertValidName-test.ts
deleted file mode 100644
index 96909d58..00000000
--- a/src/utilities/__tests__/assertValidName-test.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { expect } from 'chai';
-import { describe, it } from 'mocha';
-
-import { assertValidName } from '../assertValidName';
-
-describe('assertValidName()', () => {
-  it('passthrough valid name', () => {
-    expect(assertValidName('_ValidName123')).to.equal('_ValidName123');
-  });
-
-  it('throws for use of leading double underscores', () => {
-    expect(() => assertValidName('__bad')).to.throw(
-      '"__bad" must not begin with "__", which is reserved by GraphQL introspection.',
-    );
-  });
-
-  it('throws for non-strings', () => {
-    // @ts-expect-error
-    expect(() => assertValidName({})).to.throw('Expected name to be a string.');
-  });
-
-  it('throws on empty strings', () => {
-    expect(() => assertValidName('')).to.throw(
-      'Expected name to be a non-empty string.',
-    );
-  });
-
-  it('throws for names with invalid characters', () => {
-    expect(() => assertValidName('>--()-->')).to.throw(
-      'Names must only contain [_a-zA-Z0-9] but ">--()-->" does not.',
-    );
-  });
-
-  it('throws for names starting with invalid characters', () => {
-    expect(() => assertValidName('42MeaningsOfLife')).to.throw(
-      'Names must start with [_a-zA-Z] but "42MeaningsOfLife" does not.',
-    );
-  });
-});