Skip to content

Commit

Permalink
Add tests exercising Symbol.toStringTag and instanceOf.
Browse files Browse the repository at this point in the history
  • Loading branch information
benjamn committed Jan 26, 2021
1 parent f9e1d0a commit db4b2b8
Showing 1 changed file with 111 additions and 0 deletions.
111 changes: 111 additions & 0 deletions src/jsutils/__tests__/instanceOf-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ import { expect } from 'chai';
import { describe, it } from 'mocha';

import instanceOf from '../instanceOf';
import { SYMBOL_TO_STRING_TAG } from '../../polyfills/symbols';
import {
GraphQLScalarType,
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLUnionType,
GraphQLEnumType,
GraphQLInputObjectType,
} from '../../type/definition';

describe('instanceOf', () => {
it('fails with descriptive error message', () => {
Expand All @@ -19,4 +28,106 @@ describe('instanceOf', () => {
/^Cannot use Foo "\[object Object\]" from another module or realm./m,
);
});

describe('Symbol.toStringTag', () => {
function checkSameNameClasses(getClass) {
const Class1 = getClass('FirstClass');
const Class2 = getClass('SecondClass');

expect(Class1.name).to.equal('Foo');
expect(Class2.name).to.equal('Foo');

expect(instanceOf(null, Class1)).to.equal(false);
expect(instanceOf(null, Class2)).to.equal(false);

const c1 = new Class1();
const c2 = new Class2();

expect(getTag(c1)).to.equal('FirstClass');
expect(getTag(c2)).to.equal('SecondClass');

// In these Symbol.toStringTag tests, instanceOf returns the
// expected boolean value without throwing an error, because even
// though Class1.name === Class2.name, the Symbol.toStringTag
// strings of the two classes are different.
expect(instanceOf(c1, Class1)).to.equal(true);
expect(instanceOf(c1, Class2)).to.equal(false);
expect(instanceOf(c2, Class1)).to.equal(false);
expect(instanceOf(c2, Class2)).to.equal(true);
}

function getTag(from: any): string {
return from[SYMBOL_TO_STRING_TAG];
}

it('does not fail if dynamically-defined tags differ', () => {
checkSameNameClasses((tag) => {
class Foo {}
Object.defineProperty(Foo.prototype, SYMBOL_TO_STRING_TAG, {
value: tag,
});
return Foo;
});
});

it('does not fail if dynamically-defined tag getters differ', () => {
checkSameNameClasses((tag) => {
class Foo {}
Object.defineProperty(Foo.prototype, SYMBOL_TO_STRING_TAG, {
get() {
return tag;
},
});
return Foo;
});
});

it('does not fail for anonymous classes', () => {
checkSameNameClasses((tag) => {
const Foo = class {};
Object.defineProperty(Foo.prototype, SYMBOL_TO_STRING_TAG, {
get() {
return tag;
},
});
return Foo;
});
});

it('does not fail if prototype property tags differ', () => {
checkSameNameClasses((tag) => {
class Foo {}
(Foo.prototype: any)[SYMBOL_TO_STRING_TAG] = tag;
return Foo;
});
});

it('does not fail if computed getter tags differ', () => {
checkSameNameClasses((tag) => {
class Foo {
// $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet
get [SYMBOL_TO_STRING_TAG]() {
return tag;
}
}
return Foo;
});
});

it('is defined for various GraphQL*Type classes', () => {
function checkGraphQLType(constructor, expectedName) {
expect(getTag(constructor.prototype)).to.equal(expectedName);
const instance = Object.create(constructor.prototype);
expect(getTag(instance)).to.equal(expectedName);
expect(instanceOf(instance, constructor)).to.equal(true);
}

checkGraphQLType(GraphQLScalarType, 'GraphQLScalarType');
checkGraphQLType(GraphQLObjectType, 'GraphQLObjectType');
checkGraphQLType(GraphQLInterfaceType, 'GraphQLInterfaceType');
checkGraphQLType(GraphQLUnionType, 'GraphQLUnionType');
checkGraphQLType(GraphQLEnumType, 'GraphQLEnumType');
checkGraphQLType(GraphQLInputObjectType, 'GraphQLInputObjectType');
});
});
});

0 comments on commit db4b2b8

Please sign in to comment.