newtests/FacebookismIdx/test.js (280 lines of code) (raw):
/*
* @flow
*/
import type {Suite} from "flow-dev-tools/src/test/Suite";
const {suite, test} = require('flow-dev-tools/src/test/Tester');
module.exports = (suite(({addFile, addFiles, addCode}) => [
test('idx(object)', [
addCode('declare var idx: $Facebookism$Idx;\n').noNewErrors(),
addCode('declare var obj1: {a: ?{b: {c: number}}};').noNewErrors(),
addCode('obj1.a.b.c;\n')
.newErrors(
`
test.js:8
8: obj1.a.b.c;
^ Cannot get \`obj1.a.b\` because property \`b\` is missing in null or undefined [1]. [incompatible-use]
References:
6: declare var obj1: {a: ?{b: {c: number}}};
^^^^^^^^^^^^^^^^^ [1]
`,
),
addCode('(idx(obj1, obj => obj.a.b.c): ?number);\n').noNewErrors(),
addCode('(idx(obj1, obj => obj["a"].b.c): ?number);\n').noNewErrors(),
addCode('(idx(obj1, obj => obj.a.b.c): number);\n').
newErrors(
`
test.js:17
17: (idx(obj1, obj => obj.a.b.c): number);
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to number because null or undefined [1] is incompatible with number [2]. [incompatible-cast]
References:
17: (idx(obj1, obj => obj.a.b.c): number);
^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1]
17: (idx(obj1, obj => obj.a.b.c): number);
^^^^^^ [2]
`,
),
addCode('(idx(obj1, obj => obj.a.b.c): ?string);\n')
.newErrors(
`
test.js:20
20: (idx(obj1, obj => obj.a.b.c): ?string);
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to nullable string because number [1] is incompatible with string [2]. [incompatible-cast]
References:
6: declare var obj1: {a: ?{b: {c: number}}};
^^^^^^ [1]
20: (idx(obj1, obj => obj.a.b.c): ?string);
^^^^^^ [2]
`,
),
addCode('(idx(obj1, obj => obj["a"].b.c): number);\n')
.newErrors(
`
test.js:23
23: (idx(obj1, obj => obj["a"].b.c): number);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to number because null or undefined [1] is incompatible with number [2]. [incompatible-cast]
References:
23: (idx(obj1, obj => obj["a"].b.c): number);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1]
23: (idx(obj1, obj => obj["a"].b.c): number);
^^^^^^ [2]
`,
),
addCode('idx(obj1, obj => obj.notAProp);\n')
.newErrors(
`
test.js:26
26: idx(obj1, obj => obj.notAProp);
^^^^^^^^ Cannot get \`obj.notAProp\` because property \`notAProp\` is missing in object type [1]. [prop-missing]
References:
6: declare var obj1: {a: ?{b: {c: number}}};
^^^^^^^^^^^^^^^^^^^^^^ [1]
`,
),
addCode('idx(obj1, obj => obj.a = null);\n')
.newErrors(
`
test.js:29
29: idx(obj1, obj => obj.a = null);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot call \`idx(...)\` because the callback must only access properties on the callback parameter. [invalid-idx]
`,
),
addCode('declare var obj2: {a?: {b: {c: number}}};').noNewErrors(),
addCode('(idx(obj2, obj => obj.a.b.c): ?number);\n').noNewErrors(),
addCode('(idx(obj2, obj => obj.a.b.c): number);\n')
.newErrors(
`
test.js:37
37: (idx(obj2, obj => obj.a.b.c): number);
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to number because null or undefined [1] is incompatible with number [2]. [incompatible-cast]
References:
37: (idx(obj2, obj => obj.a.b.c): number);
^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1]
37: (idx(obj2, obj => obj.a.b.c): number);
^^^^^^ [2]
`,
),
addCode('declare var obj3: {a: null | {b: {c: number}}};').noNewErrors(),
addCode('(idx(obj3, obj => obj.a.b.c): ?number);\n').noNewErrors(),
addCode('(idx(obj3, obj => obj.a.b.c): number);\n')
.newErrors(
`
test.js:45
45: (idx(obj3, obj => obj.a.b.c): number);
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to number because null or undefined [1] is incompatible with number [2]. [incompatible-cast]
References:
45: (idx(obj3, obj => obj.a.b.c): number);
^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1]
45: (idx(obj3, obj => obj.a.b.c): number);
^^^^^^ [2]
`,
),
// Nested maybes/optionals should get unwrapped
addCode('declare var obj4: {a?: ?(?{b: number})};').noNewErrors(),
addCode('(idx(obj4, obj => obj.a.b): ?number)').noNewErrors(),
]),
test('unions', [
addCode('declare var idx: $Facebookism$Idx;\n').noNewErrors(),
addCode('declare var ab: {a:string}|{b:number};\n').noNewErrors(),
addCode('(idx(ab, _ => _.a): empty);\n')
.newErrors(
`
test.js:9
9: (idx(ab, _ => _.a): empty);
^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to empty because string [1] is incompatible with empty [2]. [incompatible-cast]
References:
6: declare var ab: {a:string}|{b:number};
^^^^^^ [1]
9: (idx(ab, _ => _.a): empty);
^^^^^ [2]
test.js:9
9: (idx(ab, _ => _.a): empty);
^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to empty because null or undefined [1] is incompatible with empty [2]. [incompatible-cast]
References:
9: (idx(ab, _ => _.a): empty);
^^^^^^^^^^^^^^^^^ [1]
9: (idx(ab, _ => _.a): empty);
^^^^^ [2]
test.js:9
9: (idx(ab, _ => _.a): empty);
^ Cannot get \`_.a\` because property \`a\` is missing in object type [1]. [prop-missing]
References:
6: declare var ab: {a:string}|{b:number};
^^^^^^^^^^ [1]
`,
),
addCode('(idx(ab, _ => _.b): empty);\n')
.newErrors(
`
test.js:12
12: (idx(ab, _ => _.b): empty);
^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to empty because number [1] is incompatible with empty [2]. [incompatible-cast]
References:
6: declare var ab: {a:string}|{b:number};
^^^^^^ [1]
12: (idx(ab, _ => _.b): empty);
^^^^^ [2]
test.js:12
12: (idx(ab, _ => _.b): empty);
^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to empty because null or undefined [1] is incompatible with empty [2]. [incompatible-cast]
References:
12: (idx(ab, _ => _.b): empty);
^^^^^^^^^^^^^^^^^ [1]
12: (idx(ab, _ => _.b): empty);
^^^^^ [2]
test.js:12
12: (idx(ab, _ => _.b): empty);
^ Cannot get \`_.b\` because property \`b\` is missing in object type [1]. [prop-missing]
References:
6: declare var ab: {a:string}|{b:number};
^^^^^^^^^^ [1]
`,
),
addCode('(idx(ab, _ => _.c): empty);\n')
.newErrors(
`
test.js:15
15: (idx(ab, _ => _.c): empty);
^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to empty because null or undefined [1] is incompatible with empty [2]. [incompatible-cast]
References:
15: (idx(ab, _ => _.c): empty);
^^^^^^^^^^^^^^^^^ [1]
15: (idx(ab, _ => _.c): empty);
^^^^^ [2]
test.js:15
15: (idx(ab, _ => _.c): empty);
^ Cannot get \`_.c\` because property \`c\` is missing in object type [1]. [prop-missing]
References:
6: declare var ab: {a:string}|{b:number};
^^^^^^^^^^ [1]
test.js:15
15: (idx(ab, _ => _.c): empty);
^ Cannot get \`_.c\` because property \`c\` is missing in object type [1]. [prop-missing]
References:
6: declare var ab: {a:string}|{b:number};
^^^^^^^^^^ [1]
`,
),
]),
test('idx(classInst)', [
addCode('declare var idx: $Facebookism$Idx;\n').noNewErrors(),
addCode('class Foo1 { a: ?Foo1; b: ?number; }\n').noNewErrors(),
addCode('class Foo2 { a: Foo2 | void; b: ?number; }\n').noNewErrors(),
addCode('class Foo3 { a: Foo3 | null; b: ?number; }\n').noNewErrors(),
addCode('(idx(new Foo1(), o => o.a.b): ?number);\n').noNewErrors(),
addCode('(idx(new Foo1(), o => o.a.b): number);\n')
.newErrors(
`
test.js:18
18: (idx(new Foo1(), o => o.a.b): number);
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to number because null or undefined [1] is incompatible with number [2]. [incompatible-cast]
References:
6: class Foo1 { a: ?Foo1; b: ?number; }
^^^^^^^ [1]
18: (idx(new Foo1(), o => o.a.b): number);
^^^^^^ [2]
test.js:18
18: (idx(new Foo1(), o => o.a.b): number);
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to number because null or undefined [1] is incompatible with number [2]. [incompatible-cast]
References:
18: (idx(new Foo1(), o => o.a.b): number);
^^^^^^^^^^^^^^^^^^^^^^^^^^^ [1]
18: (idx(new Foo1(), o => o.a.b): number);
^^^^^^ [2]
`,
),
addCode('idx(new Foo1(), o => o.a = null);\n')
.newErrors(
`
test.js:21
21: idx(new Foo1(), o => o.a = null);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot call \`idx(...)\` because the callback must only access properties on the callback parameter. [invalid-idx]
`,
),
]),
test('idx(array)', [
addCode('declare var idx: $Facebookism$Idx;\n').noNewErrors(),
addCode('declare var arr1: Array<?Array<number>>;\n').noNewErrors(),
addCode('declare var arr2: Array<Array<number> | void>;\n').noNewErrors(),
addCode('declare var arr3: Array<Array<number> | null>;\n').noNewErrors(),
addCode('(idx(arr1, arr => arr[0][0]): ?number);\n').noNewErrors(),
addCode('(idx(arr2, arr => arr[0][0]): ?number);\n').noNewErrors(),
addCode('(idx(arr3, arr => arr[0][0]): ?number);\n').noNewErrors(),
]),
test('idx(nonObject)', [
addCode('declare var idx: $Facebookism$Idx;\n').noNewErrors(),
addCode('(idx(42, n => n): ?number);\n').noNewErrors(),
addCode('(idx(42, n => n): number);\n')
.newErrors(
`
test.js:9
9: (idx(42, n => n): number);
^^^^^^^^^^^^^^^ Cannot cast \`idx(...)\` to number because null or undefined [1] is incompatible with number [2]. [incompatible-cast]
References:
9: (idx(42, n => n): number);
^^^^^^^^^^^^^^^ [1]
9: (idx(42, n => n): number);
^^^^^^ [2]
`,
),
addCode('idx(42, n => n.nope);\n')
.newErrors(
`
test.js:12
12: idx(42, n => n.nope);
^^^^ Cannot get \`n.nope\` because property \`nope\` is missing in \`Number\` [1]. [prop-missing]
References:
12: idx(42, n => n.nope);
^^ [1]
`,
),
]),
test('idx() weird edge cases', [
addCode('declare var idx: $Facebookism$Idx;\n').noNewErrors(),
// Using an annotation obscures the type wrapper mechanism that idx() uses
// around the parameter it passes to the callback
addCode('(idx({}, (obj: Object) => obj.a.b.c): ?number);\n')
.noNewErrors(),
// Can't do anything with the callback parameter other than get elements and
// properties off of it
addCode('idx({}, obj => obj());\n')
.newErrors(
`
test.js:9
9: idx({}, obj => obj());
^^^^^^^^^^^^^^^^^^^^^ Cannot call \`idx(...)\` because the callback must only access properties on the callback parameter. [invalid-idx]
`,
),
]),
]): Suite);