Skip to content

Commit f7b94d1

Browse files
authored
Merge pull request #717 from wincent/glh/degrade-to-warn
Soften name validation warnings to avoid CI issues
2 parents 56e8240 + 44a2cff commit f7b94d1

File tree

3 files changed

+164
-6
lines changed

3 files changed

+164
-6
lines changed

src/type/__tests__/validation-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,9 @@ describe('Type System: Objects must have fields', () => {
356356

357357
it('warns about an Object type with reserved named fields', () => {
358358
/* eslint-disable no-console */
359-
const realConsoleError = console.error;
359+
const realConsoleWarn = console.warn;
360360
const calls = [];
361-
console.error = function () {
361+
console.warn = function () {
362362
calls.push(Array.prototype.slice.call(arguments));
363363
};
364364
try {
@@ -371,7 +371,7 @@ describe('Type System: Objects must have fields', () => {
371371
'Name "__notPartOfIntrospection" must not begin with "__", which is reserved by GraphQL introspection.'
372372
);
373373
} finally {
374-
console.error = realConsoleError;
374+
console.warn = realConsoleWarn;
375375
}
376376
/* eslint-enable no-console */
377377
});
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/**
2+
* Copyright (c) 2015, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
import { describe, it } from 'mocha';
11+
import { expect } from 'chai';
12+
import { formatWarning } from '../assertValidName';
13+
14+
/**
15+
* Helper for dedenting indented template literals. This helps us to
16+
* keep the tests pretty.
17+
*/
18+
function dedent(string) {
19+
// Get lines, discarding empty leading and trailing lines.
20+
const lines = string.replace(/^[ \t]*\n|\n[ \t]*$/g, '').split('\n');
21+
22+
// Find smallest indent.
23+
const indent = lines.reduce((currentMinimum, line) => {
24+
const whitespace = line.match(/^ +/);
25+
return Math.min(
26+
whitespace ? whitespace[0].length : 0,
27+
currentMinimum
28+
);
29+
}, Infinity);
30+
31+
// Remove indent from each line.
32+
return lines.map(line => line.slice(indent)).join('\n');
33+
}
34+
35+
/**
36+
* Convenience method for creating an Error object with a defined stack.
37+
*/
38+
function createErrorObject(message, stack) {
39+
const error = new Error(message);
40+
error.stack = stack;
41+
return error;
42+
}
43+
44+
describe('formatWarning()', () => {
45+
it('formats given a Chrome-style stack property', () => {
46+
const chromeStack = dedent(`
47+
Error: foo
48+
at z (<anonymous>:1:21)
49+
at y (<anonymous>:1:15)
50+
at x (<anonymous>:1:15)
51+
at <anonymous>:1:6
52+
`);
53+
const error = createErrorObject('foo', chromeStack);
54+
expect(formatWarning(error)).to.equal(dedent(`
55+
foo
56+
at z (<anonymous>:1:21)
57+
at y (<anonymous>:1:15)
58+
at x (<anonymous>:1:15)
59+
at <anonymous>:1:6
60+
`));
61+
});
62+
63+
it('formats given a Node-style stack property', () => {
64+
const nodeStack = dedent(`
65+
Error: foo
66+
at z (repl:1:29)
67+
at y (repl:1:23)
68+
at x (repl:1:23)
69+
at repl:1:6
70+
at ContextifyScript.Script.runInThisContext (vm.js:23:33)
71+
at REPLServer.defaultEval (repl.js:340:29)
72+
at bound (domain.js:280:14)
73+
at REPLServer.runBound [as eval] (domain.js:293:12)
74+
at REPLServer.onLine (repl.js:537:10)
75+
at emitOne (events.js:101:20)
76+
`);
77+
const error = createErrorObject('foo', nodeStack);
78+
expect(formatWarning(error)).to.equal(dedent(`
79+
foo
80+
at z (repl:1:29)
81+
at y (repl:1:23)
82+
at x (repl:1:23)
83+
at repl:1:6
84+
at ContextifyScript.Script.runInThisContext (vm.js:23:33)
85+
at REPLServer.defaultEval (repl.js:340:29)
86+
at bound (domain.js:280:14)
87+
at REPLServer.runBound [as eval] (domain.js:293:12)
88+
at REPLServer.onLine (repl.js:537:10)
89+
at emitOne (events.js:101:20)
90+
`));
91+
});
92+
93+
it('formats given a Firefox-style stack property', () => {
94+
const firefoxStack = dedent(`
95+
z@debugger eval code:1:20
96+
y@debugger eval code:1:14
97+
x@debugger eval code:1:14
98+
@debugger eval code:1:5
99+
`);
100+
const error = createErrorObject('foo', firefoxStack);
101+
expect(formatWarning(error)).to.equal(dedent(`
102+
foo
103+
z@debugger eval code:1:20
104+
y@debugger eval code:1:14
105+
x@debugger eval code:1:14
106+
@debugger eval code:1:5
107+
`));
108+
});
109+
110+
it('formats given a Safari-style stack property', () => {
111+
const safariStack = dedent(`
112+
z
113+
y
114+
x
115+
global code
116+
evaluateWithScopeExtension@[native code]
117+
_evaluateOn
118+
_evaluateAndWrap
119+
evaluate
120+
`);
121+
const error = createErrorObject('foo', safariStack);
122+
expect(formatWarning(error)).to.equal(dedent(`
123+
foo
124+
z
125+
y
126+
x
127+
global code
128+
evaluateWithScopeExtension@[native code]
129+
_evaluateOn
130+
_evaluateAndWrap
131+
evaluate
132+
`));
133+
});
134+
135+
it('formats in the absence of a stack property', () => {
136+
const error = createErrorObject('foo');
137+
expect(formatWarning(error)).to.equal('foo');
138+
});
139+
});

src/utilities/assertValidName.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
const NAME_RX = /^[_a-zA-Z][_a-zA-Z0-9]*$/;
12+
const ERROR_PREFIX_RX = /^Error: /;
1213

1314
// Ensures console warnings are only issued once.
1415
let hasWarnedAboutDunder = false;
@@ -28,12 +29,13 @@ export function assertValidName(
2829
if (!isIntrospection && name.slice(0, 2) === '__' && !hasWarnedAboutDunder) {
2930
hasWarnedAboutDunder = true;
3031
/* eslint-disable no-console */
31-
if (console && console.error) {
32+
if (console && console.warn) {
3233
const error = new Error(
3334
`Name "${name}" must not begin with "__", which is reserved by ` +
34-
'GraphQL introspection.'
35+
'GraphQL introspection. In a future release of graphql this will ' +
36+
'become a hard error.'
3537
);
36-
console.error(error.stack || String(error));
38+
console.warn(formatWarning(error));
3739
}
3840
/* eslint-enable no-console */
3941
}
@@ -43,3 +45,20 @@ export function assertValidName(
4345
);
4446
}
4547
}
48+
49+
/**
50+
* Returns a human-readable warning based an the supplied Error object,
51+
* including stack trace information if available.
52+
*/
53+
export function formatWarning(error: Error): string {
54+
let formatted = '';
55+
const errorString = String(error).replace(ERROR_PREFIX_RX, '');
56+
const stack = error.stack;
57+
if (stack) {
58+
formatted = stack.replace(ERROR_PREFIX_RX, '');
59+
}
60+
if (formatted.indexOf(errorString) === -1) {
61+
formatted = errorString + '\n' + formatted;
62+
}
63+
return formatted.trim();
64+
}

0 commit comments

Comments
 (0)